# Лекция 22. Системы общего назначения

## Содержание

- [Лекция 22. Системы общего назначения](#Лекция-22-Системы-общего-назначения)
  - [Содержание](#Содержание)
  - [Микропроцессоры](#Микропроцессоры)
  - [История x86](#История-x86)
  - [Тик-так](#Тик-так)
  - [Coffee lake](#coffee-lake)
    - [Front-end](#front-end)
    - [Execution Engine](#execution-engine)
  - [Gen9.5](#gen95)
  - [AMD Zen](#amd-zen)
  - [Из чего состоит компьютер?](#Из-чего-состоит-компьютер)
  - [Основные материалы лекции](#Основные-материалы-лекции)

## Микропроцессоры

Для начала повторим классификацию микропроцессоров.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_01.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_01.png)

*Рис. 1. Классификация микропроцессоров.*

**Микропроцессоры общего назначения** – нужны для решения любых задач, они не предназначен для специализированных задач. Для них мы используем **специализированные микропроцессоры**.

**Специализированные микропроцессоры** – альтернатива, которую мы можем разделить на **микроконтроллеры** и **процессоры цифровой обработки сигналов**. Про микроконтроллеры мы подробнее поговорили на прошлой лекции.

**Процессоры цифровой обработки сигналов** – фактически это те же **микроконтроллеры**, но они больше ориентированы на цифровую обработку сигналов.

В этой лекции мы рассмотрим процессоры общего назначения.

## История x86

Процессоры архитектуры **x86** имеют архитектуру с полным набором команд, то есть поддерживают большое количество инструкций с разной шириной.

Впервые архитектура **x86** была представлена компанией Intel в 1978 году (Intel **8086**). Следующие версии **8086** стали совершенствовать первую версию добавлением новых инструкций, таймеров, контроллеров, защищенных режимов и т.д. Полный список представлен в таблице 1.

| Версия      |                       Что было добавлено                        | Год выпуска |
|:------------|:---------------------------------------------------------------:|:-----------:|
| Intel 8086  |          16-битный, 98 инструкций, 7 режимов адресации          |    1978     |
| Intel 80186 |     Новые инструкции, КПДП, таймеры, контроллер прерывания      |    1982     |
| Intel 80286 |              Защищенный режим, виртуальная память               |    1982     |
| Intel 80386 |        32-битный, страничная организация, до 4 Гб памяти        |    1985     |
| Intel 80486 |                   Сопроцессор, 150 инструкций                   |    1989     |
| P6          | Суперскалярный CISC, RISC-ядро, предсказание условных переходов |    1995     |
| MMX         |  **M**ulti**m**edia E**x**tensions (мультимедийные расширения)  |    1997     |

*Таблица 1. Развитие процессора Intel 8086.*

## Тик-так

Когда Intel делают свои процессоры они используют подход **"Тик-так"**. Суть его заключается в том, что они в одном году разрабатывают новую архитектуру (**тик**), а в следующем осваивают новый тех. процесс (**так**). На рисунке 2 можно увидеть как работал **"Тик-так"** до 2015 года, сейчас это работает немного "криво", но общая идея понятна.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_02.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_02.png)

*Рис. 2. Подход Тик-так.*

## Coffee lake

Рассмотрим микроархитектуру процессора **Coffee Lake**, выпущенного в 2017-ом году. Она состоит из трех основных блоков:

- **Memory Subsystem** (подсистема памяти);
- **Execution Engine** (RISC-ядра);
- **Front-end** (CISC-оболочка поверх **Execution Engine**).

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_03.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_03.png)

*Рис. 3. Микроархитектура Coffee Lake.*

Разберём каждый блок подробнее:

### Front-end

Из **кеш-памяти** за один такт считывается сразу 16 байт CISC-инструкций, которые подаются в **Буфер предварительного декодирования** (**Instruction Fetch & PreDecode**). **x86**-инструкции сложны, имеют переменную длину, несогласованное кодирование и могут содержать несколько операций. Буфер предварительного декодирования выполняет разметку границ инструкций. Это довольно сложная задача, так как длина каждой инструкции может варьироваться от одного байта до пятнадцати. Кроме того, для определения длины может потребоваться просмотр нескольких первых её байт. Помимо разметки границ, декодируются префиксы инструкции, которые затем проверяются на различные свойства, например ветвления[\[1\]](https://en.wikichip.org/wiki/intel/microarchitectures/skylake#Front-end).

Из блока **Буфера предварительного кодирования** выходят до 6 макро-операций, которые затем подаются в блок **очереди инструкций**, где (в некоторых случаях) благодаря **Macro-Fusion** две последовательно идущие инструкции могут быть преобразованы в одну.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_04.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_04.png)

*Рис. 4. Пример объединения двух инструкций в блоке **Macro-Fusion**[\[2\]](https://en.wikichip.org/wiki/intel/microarchitectures/skylake#Instruction_Queue_.26_MOP-Fusion).*

За такт может произойти только одно подобное объединение. Иными словами, даже если в очереди окажется две пары подходящих для объединения инструкций, объединена будет только первая пара (кроме того, есть и другие ограничения по объединению)[\[3\]](https://en.wikichip.org/wiki/macro-operation_fusion#Mechanism).

Почему этап **Macro-Fusion** не может быть реализован на этапе компиляции программы? Дело в том, что в результате этого преобразования, результирующая макро-операция уже не является какой-то стандартной x86-инструкцией. Вместо этого, она становится какой-то специальной инструкцией, которая в дальнейшем может быть декодирована и исполнена только данной микроархитектурой процессора.

В наборе инструкций x86 нет операции условного перехода в том виде, в котором они представлены в ISA RISC-V. Вместо этого, условный переход делится на две инструкции:

- инструкция вычисления результата условия
- инструкция прыжка в зависимости от результата условия

Таким образом, каждый такой переход накладывает на процессор штраф в одну дополнительную инструкцию. При создании новых процессоров уже невозможно избавиться от этого штрафа через изменение существующей ISA x86 (из-за проблем с обратной совместимостью программ), именно поэтому и был создан данный блок[\[4\]](https://arxiv.org/pdf/1607.02318.pdf).

Из **Instruction Queue** выходит 5 макро-инструкций (с учётом того, что две из шести инструкций могли быть объединены), и попадают в **5-Way Decode** (**пятисекционный дешифратор**).

**Пяти секционный дешифратор** преобразует макро-операции в микро-операции (которые похожи на RISC-инструкции). Простые макро-операции попадают в **Simple Decoder** и преобразуются в одну микро-операцию. Более сложные попадают в **Complex Decoder**. Самые сложные макро-операции полагаются на память микропрограмм **MicroCode Sequencer** (где написана целая микропрограмма для исполнения конкретной макро-операции). Помимо прочего здесь подключен **Stack Engine** — аппаратный блок, позволяющий вычислять обновленное значение указателя на стек (без исполнения соответствующей микро-операции).

**Предсказатель результата ветвлений** (**Branch Predictor**) говорит о том какой адрес необходимо использовать для получения новых инструкций еще до вычисления результата ветвления.

**Буфер декодированного потока инструкций** (**Decoded Stream Buffer**) содержит декодированные ранее операции. В случае, если будут получены макро-операции, которые уже были недавно декодированы, данный буфер сможет сразу же выдать готовые микро-инструкции.

В блоке **MUX** мы имеем набор инструкций, которые уже нужно выполнить. От туда они попадают в **Allocation Queue**, где мы также имеем **Micro-Fusion** для дополнительной доработки микро инструкций. **Loop Stream Detector** необходим для запоминания последних 18 инструкций и определяет есть ли цикл. Из этого блока мы переходим к **Execution Engine**.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_05.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_05.png)

*Рис. 5. Front-end Coffee Lake.*

### Execution Engine

**ReOrder Buffer** получает инструкции и переименовывает используемые ими регистры, чтобы избежать конфликтов (чтение после записи, попытка записи в один регистр и т.д.). Переименовывание означает использование теневых регистров из **RAT - Register Alias Table** (дополнительных регистров), они необходимы для того, чтобы не нарушать порядок записи в одну ячейку и записать результат в теневой регистр. Из блока **ReOrder Buffer** выходят микро инструкции с известными адресами, куда они будут сохранены, переименованными регистрами и т.д. Они попадают в **Scheduler Unified Reservation Station**

В **Scheduler Unified Reservation Station (планировщик)** происходит диспетчеризация, то есть микро инструкции раздаются на различные порты. **Планировщик** имеет два файла регистров для целых чисел и векторов. Именно в этих файлах регистров хранятся выходные данные операндов. На выходе каждого порта стоят функциональные блоки (**EUs - Execution Units**). Планировщик удерживает микро-операции, пока они ожидают выполнения. Микро-операция может ожидать операнда, который еще не прибыл (например, выбран из памяти или в настоящее время вычисляется из других микро-операций) или потому, что необходимый ему исполнительный блок занят. Как только микро-операция готова, она отправляется через назначенный порт. Планировщик будет отправлять самую старую готовую инструкцию для выполнения на каждом из восьми портов в каждом цикле. Каждый из этих портов выполняет свои задачи - целочисленное ALU, целочисленное деление, векторные операции и т.п. Некоторые из этих блоков подключены к подсистеме памяти (**Memory Subsystem**).

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_06.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_06.png)

*Рис. 6. Execution Engine Coffee Lake.*

**Memory Subsystem** – подсистема памяти, отвечающая за загрузку, запросы к сохранению и упорядочивание. Данные попадают в **Load Buffer** и **Store Buffer**, подключенные к кешу первого уровня **L1 Data Cache**, который в свою очередь передаёт всё в кеш второго уровня. В каждом цикле можно выполнить одну операцию, т. е. L1 может либо получать данные от L2, либо отправлять данные в буферы загрузки/сохранения каждый цикл, но не то и другое.  **L2 Cache** уже является общим для команд и для данных.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_07.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_07.png)

*Рис. 7. Memory Subsystem Coffee Lake.*

Выше мы рассмотрели одно ядро. **Coffee Lake** может иметь 4, 6 и 8 ядер (на рисунке 8 представлен 4-ядерный процессор). Подсистемы памяти каждого ядра объединяются в **кольцевую шину**.  **Кольцевая шина** передаёт информацию по кругу, благодаря чему устраняются конфликты, допустим когда несколько устройств хотят завладеть шиной. В правой части находится **System Agent**. Он связан с взаимодействием с памятью, дисплеем и другими внешними устройствами.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_08.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_08.png)

*Рис. 8. четырёхъядерный процессор Coffee Lake.*

Метод **кольцевой шины** имеет и минусы – если её расширять, то её пропускная способность падает.

## Gen9.5

**Gen9.5** – графическое ядро. Оно состоит из

- **Command Streamer** – устройство, которое управляет потоком исполнения.
- **EU (Execution Unit)** – исполнительные устройства, производящие вычисления.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_09.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_09.png)

*Рис. 9. Графическое ядро Gen9.5.*

## AMD Zen

Для сравнения рассмотрим микро архитектуру **AMD Zen**. Многие блоки совпадают с **Coffee Lake**, поэтому акцентируем внимание на отличиях: в данной реализации инструкции сортируются в зависимости от того целочисленные они (Integer) или с плавающей запятой (FP/SIMD). Этот пример используется в ознакомительных целях - показать, что есть и другие микро архитектуры.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_10.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_10.png)

*Рис. 10. Микроархитектура AMD Zen.*

## Из чего состоит компьютер?

Выйдем на уровень системы. Ранее мы рассматривали только **Центральный Процессор (ЦП)**. Сейчас же мы разберём из чего в целом состоит компьютер:

- **Центральный процессор**
- **Генератор тактовых импульсов**

- **Чипсет** – набор микросхем, управляющих общением процессора, памяти и периферийных устройств. Обычно состоит из двух микросхем:
  - **Северный мост** — это контроллер-концентратор памяти, который взаимодействует с памятью и высокоскоростными устройствами `PCI-E`. Чтобы ускорить общение с высокоскоростной шиной в современных процессорах северных мост стали встраивать в **ЦП**.
  - **Южный мост** — контроллер-концентратор ввода-вывода, который связан с медленными устройствами (BIOS, PCI, SATA и т.п.).

- **BIOS** – базовая система ввода-вывода. С загрузки **BIOS** начинается включение компьютера: **BIOS** копирует свою программу в основную память, после чего передает управление процессору, чтобы тот проверил: какое оборудование подключено, как его необходимо сконфигурировать и в рабочем ли состоянии оно находится (т.е. сканирует и конфигурирует систему).

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_11.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_11.png)

*Рис. 11. Материнская плата в схематичном варианте.*

На рис. 12 представлена иллюстрация расположения **северного** и **южного моста** на материнской плате.
Обратите внимание на то, что **северный мост** находится ближе к процессору, а **южный** к периферии, USB и т.п.

![../.pic/Lectures/22.%20General%20purpose%20systems/fig_12.png](../.pic/Lectures/22.%20General%20purpose%20systems/fig_12.png)

*Рис. 12. Материнская плата.*

## Основные материалы лекции

1. [Ссылка](https://www.youtube.com/watch?v=w7CcAgTtL6k&list=PL0def37HEo5KHPjwK7A5bd4RJGg4djPVf&index=22) на видеозапись лекции
