понедельник, 23 ноября 2015 г.

Устройство центрального процессора


Ядро процессора

Intel'овские процессоры типа Core2Duo (Core2Quard, i3, i5, i7) основаны на микроархитектуре Intel Core. Ядра соединены общими шинами данных, адреса и управления.
Иллюстрация работы конвейера.
Работа процессора без конвейера.
Выполнение команды процессором состоит из нескольких этапов: выборка команды из памяти, декодирование команды, выполнение команды, запись результатов. Если раньше все эти этапы происходили последовательно, то теперь применяются конвейеры — по мере освобождения от работы устройств (выборки, декодировки, выполнения и записи), они переходят к обработке следующей команды программы. Такой принцип позволяет постоянно держать ядро загруженным. Однако если выполнимый код пестрит длинными переходами и вообще представляет из себя творение жителей индии, то все плюсы конвейеризации сходят на нет.

Элементы процессора


  1. Дешифратор (декодер) команд получает на вход код операции из памяти, устройство управления управляет (как ни странно) всеми остальными элементами процессором в соответствии со смыслом команды.
  2. АЛУ - арифметическо-логическое устройство. Это основное устройство процессора, единственная задача которого — обрабатывать данные. У АЛУ есть два входа (физически у них есть буферы, но это мало кого волнует) и один выход, соединенный с аккумулятором. Так же АЛУ имеет доступ к регистру состояния.
  3. Аккумулятор — этот один из регистров процессора. Регистр — это элемент процессора в котором можно хранить число определенной длинны (или разрядности, например 8-битные, 16-битные регистры). Аккумулятор напрямую подключен к АЛУ и после выполнения операции в нем оказывается результат вычисления.
  4. Регистр состояния процессора — отражает что произошло с процессом за предыдущий такт. Разрядность регистра состояние варьируется. Каждый бит регистра — это признак (флаг) определенного события. Среди таких флагов всегда встречается флаг нулевого результата (Zero), флаг отрицательного результата (Sign) и флаг переноса (Carry). Эти флаги активно используются в командах условных переходов, которые мы рассмотрим в разделе "команды".
  5. Программный счетчик — указывает текущий адрес в памяти. Его разрядность должна совпадать с разрядностью шины данных.
  6. Регистр команды — в него загружается код команды. У некоторых процессоров он рассчитан не на одну команду, а на несколько — чтобы не тратить драгоценное время/такты для доступа к памяти.
  7. Указатель стека — этот регистр указывает на адрес верхнего элемента стека. У всех современных процессоров элементы стека хранятся в памяти, в отличие от i4004, у которого небольшой стек был организован прямо в микросхеме процессора.
  8. Регистры общего назначения (РОН) — регистры со почти свободным чтением/записью. Однако у некоторых процессоров доступ к регистрам может быть особенным, например в них нельзя писать напрямую.
  9. Шины — служат для коммуникации процессора с внешними устройствами. Физически шина представляет набор проводников. Каждый сигнал шины называется линией.
  10. Шина данных — служит для обменом данными с запоминающим устройствами. В «культурных» процессорах разрядность шины данных совпадает с разрядностью процессора.
  11. Шина адреса — служит для обмена адресом с запоминающим устройством. Её разрядность может быть и больше, чем разрядность процессора и определяет сколько памяти процессор может адресовать. Максимальное двоичное число, которое по ней можно передать будет являться верхней физической границей памяти (для 16-битной шины это 11111111'11111111 = 65536 бит).
  12. Шина управления — позволяет процессору обмениваться управляющими сигналами с периферией. Среди сигналов шины управления всегда есть сброса (RST, RESET или что-то похожее). Набор остальных сигналов определяется тем, какие еще дополнительные элементы разработчики включили в процессор. Отдельно следует рассмотреть сигнал NMI — запрос на не маскируемое прерывание (Non masked intrrupt).

Прерывания

Прерывания — это механизм, позволяющий «отвлечь» процессор от выполнения основной программы и обратить его внимание на (начать выполнять) подпрограмму обработки прерывания.
У процессора есть большое количество прерываний. Всех их можно программно отключить, кроме одного — того самого NMI. Это прерывание будет обрабатываться всегда.
Как только процессор получает сигнал прерывания он переходит по «вектору прерывания» (все эти векторы процессор знает заранее) — адресу памяти, с которого начинается программный код обработчика прерывания. На время обработки прерывания остальные лучше отключить. Обработка прерывания заканчивается командой возврата из прерывания (см. ниже).

Команды

Команды имеют свой код (номер, код операции), аргументы (если необходимы) и запись на языке ассемблера (которая, при знании английского языка, может объяснить суть команды). Однако мнемоника (запись команды) для каждого процессора своя.

Команды можно систематизировать по назначению:
  1. Команды загрузки (обмена, пересылки) — записывают значение в регистр, взятое из другого регистра или указанное числовое значение (LD - LoaD, MOV - MOVe). К этим командам можно причислить команды работы со стеком (PUSH — помещение элемента на вершину стека, POP — снятие числа с вершины стека).
  2. Арифметические и логические команды. Первую подгруппу представляют все виды сложения (ADD) и вычитания (SUB), инкремента и декремента (INC, DEC — увеличение и уменьшение значения на единицу), а в некоторых отдельных случаях и команды умножения и деления (MUL, DIV). Вторая группа — это команды, выполняющие логические операции (AND, OR, XOR) и команда сравнения (CMP - CoMPare) Команда сравнения устанавливает флаги регистра состояния, описывая это число. Например, если число -4, то установиться флаг Sign, если 0 — то флаг Zero.
  3. Битовые команды, команды сдвига и вращения. Эти команды позволяют вручную установить значение определенного бита регистра, сдвинуть его биты влево (SHL, ROL) или вправо (SHR, ROR), сохраняя сдвинутые биты или нет.
  4. Команды переходов управляют содержимым программного счетчика. Переходы могут быть безусловными или условными. Безусловные переходы бывают абсолютными (JMP - JuMP), или относительными (RJMP - Relative JuMP). В случае относительного перехода к значению программного счетчика прибавляется число аргумента, и процессор станет выполнять N-ную по счету команду от текущей. Условный переход будет выполняться только при наличии определенного флага состояния. Обычно у каждой команды условного перехода есть «антипод»: JRC (переход при наличии флага Carry), JNC (переход, если флага Carry нет), JRZ (переход при наличии флага Zero), JRZ (переход, если флага Zero нет) и так далее.
  5. Команды вызова и возврата. Команда переходов не может сохранить адрес, с которого мы перешли, а команда (они опять же могут быть условным или безусловными) CALL помещает на вершину стека адрес (в случае если адрес записывается большим числом байт, чем может вместить стек, то адрес разбивается. Например, для 8-битных процессоров с 16-битной адресацией в стек будут помещены два значения, которые будут называться старший и младший байт адреса), с которого мы перешли, чтобы потом командой RET мы могли вернуться к месту откуда ушли (и одновременно с этим убрать с вершины стека значение адреса). Команды RETI и RETN используются для возврата из подпрограмм обработки прерываний (о них читать в соответствующем разделе).
  6. Команды ввода-вывода. Процессор даже не подозревает что у него есть такие устройства ввода-вывода как клавиатура и монитор. Со всеми устройствами он работает используя порты или DMA (о работе с периферией читать в соответствующем разделе). И для работы с ними используется всего две примитивные команды IN (получение данных из порта) и OUT (запись данных в порт).
  7. Команды управления процессором. К этой группе относятся команды запрета прерываний (DI - Disable Interrupts), разрешения прерываний (EI - Enable Interrupts), остановки выполнения до получения прерывания (HALT).

Еще немного о командах. Процессоры по "сложности" и количеству команд, разделяются на RISC и CISC. В RISC-процессорах, как правило команд больше, но они элементарны по своей сути, а в CISC команды сложные. Количество тактов на команду, как правило в RISC процессорах меньше, чем в CISC.

Работа с периферийными устройствами

Для работы с периферийными устройствами используется либо DMA (прямой доступ к памяти) - устройство само пишет или читает данные в/из памяти, либо порты ввода-вывода. Первый способ быстрее, однако требует большей "интеллектуальности" от устройств ввода-вывода, в то время как второй способ реализации частично (в зависимости от процессора) предоставляется процессором (речь идет о шине управления).

Грубо система с использованием портов выглядит примерно так: шины адреса и данных разделены между памятью и отдельной микросхемой - "оператором устройств". Для определения чего именно хочет процессор: записать/считать из памяти или из порта, используются специальные линии управления процессора. Если производители не мучаясь вывели на шину управления сигналы: READ IO (чтение с устройств), WRITE IO (запись на устройства), READ MEM (чтение памяти), WRITE MEM (запись в память) то потребуется дополнительная схема, которая будет переключать шину адреса и данных с микросхем памяти (ОЗУ и ПЗУ, из которых считываются команды) на микросхему портов (которая раздает или получает данные с периферийных устройств) и обратно.

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

Частота работы

Каждый пик это сигнал процессору продолжать работу

Процессор подключен через FSB (Front Side Bus) к контроллеру памяти (который очень часто называют не отражающим суть названием «северный мост»). Поэтому частота FSB определяет скорость работы с контроллером памяти. Частота её отнюдь не равна частоте процессора, а что-то около её половины.

Частота процессора (а точнее не его, а генератора тактовых импульсов) распространяется на все ядра и часто имеет способы регулировки, например в зависимости от нагрузки на процессор (технология Turbo Boost от Intel). В общем упрощенном случае каждая инструкция процессором должна выполняться за один-два такта. К примеру, если частота составляет 2 ГГц, то выполняется около 2 миллиардов тактов в секунду. Однако, мир не совершенен, и большая часть команды x86 выполняется за гораздо большее число тактов — операция деления выполняется аж за 40 тактов.
Ведь, допустим, команда ADD (операция сложения) на частоте 8 МГц выполняется за два такта. Используем знания математики и физики. Частота измеряется в Герцах а так же в 1/секунда. Получается чтобы получить длительность (т.е. количество секунд) одного колебания, надо поделить частоту на единицу. Тогда для 8 МГц (это 8 миллионов) один такт длиться 0,000000125 секунды (ноль целых 125 миллионных). И чтобы получить длительность выполнения команды ADD нам нужно умножить длительность одного такта на количество тактов для выполнения определенной команды. Отсюда имеем, что ADD будет выполняться за 0,00000025 секунды.
А теперь повторим те же манипуляции для частоты 16 МГц. Стоит заметить, что количество тактов на команду не зависит от частоты, а от самого процессора. Получаем что один такт на частоте 16 МГц длиться 0,000000062 секунды. Тогда ADD на частоте 16 МГц будет выполняться за 0,000000125 секунды.
А теперь сравним. На частоте 8 МГц ADD выполняется за 0,00000025 секунды, а на частоте 16 МГц за 0,000000125 секунды. В первом случае команда ADD будет выполняться дольше, а следовательно во втором случае в два раза быстрее. Получается, что увеличение частоты повлекло за собой уменьшение времени выполнения команды ADD.
А теперь, чтобы подтвердить, что "увеличение частоты процессора должно увеличивать количество операций/секунду" проводим следующий эксперимент. Надо посчитать количество выполненных операций ADD на частоте 8 МГц и на частоте 16 МГц за пол минуты (30 секунд). Делим 30 секунд на длительность выполнения одной команды на разных частотах, и получаем количество выполненных команд. 120 миллионов операций ADD за 30 секунд на частоте 8 МГц (80/0,00000025=120 000 000). 240 миллионов операций ADD за 30 секунд на частоте 16 МГц (30/0,000000125=240 000 000).
Действительно, увеличение частоты увеличивает количество операций в единицу времени секунду

Кэш-память

Кэш-память используется для ускорения выполнения программы. Вместо того, чтобы чтобы процессору самостоятельно обращаться к памяти (третий по скорости доступа элемент компьютера) и считывать оттуда код команды, специальная схема периодически подгружает части памяти в кэш процессора (а это уже второй элемент по скорости доступа — после регистров процессора), уже из которого он считывает данные.
Кэш-память многоуровневая:
  1. Кэш первого уровня (L1) размещена непосредственно на кристалле процессоре и обычно делится на память для команд и для данных. L1 работает на частоте процессора.
  2. Кэш второго уровня (L2) тоже расположен на кристалле, однако в многоядерных процессорах он один на все ядра и работает на другой частоте (чаще всего половина частоты процессора).
  3. Кэш третьего уровная (L3) большого размера. Так же сущестувет (но встречается крайне редко) кэш четвертого уровня.
Кэш память физически реализована на быстрых, но дорогих (в том смысле, что на хранение одного бита уходит много транзисторов) SRAM элементах.

Режимы работы и адресация

Сейчас платформа x86 представляет собой зоопарк инструкций и способов адресации, обеспечивающих совместимость со всеми процессорами ряда x86 (8086, 80186, 80286, 80386, 80486) а так же обладающая дополнительным костылями.
Пять режимов работы:
  1. реальный - обычный для x86 режим, использующий сегментую адресацию. Так же есть функции защиты памяти;
  2. защищенный - существует со времен с i80286. Перерабатывался множество раз, однако сохранялась идея более хитрой системы адресации памяти и уровни привилегий. С i80386, в котором появилась возможность использовать 32-битные данные (в том числе и адреса), необходимость в сегментной системе адресаций вроде-бы отпала, но она продолжает использоваться;
  3. виртуальный 8086 - образно говоря, это режим физической эмуляции intel 8086. Приоритет программы, работающей в таком режиме ниже всего;
  4. 64-битный режим - здоровенный костыль для работы с 64-битными данными. Разработан AMD, после чего куплен Intel'ом и расширен парой команд;
  5. смешанный.

Расширенные наборы инструкций

  1. MMX [57 (46) инструкций] мультимедийные команды (разработан в Израиле, применен в Pntium MMX).
  2. SSE [70 инсутркций] — вычисления с плавающей точкой, введен с Pentium3.
  3. SSE2 [144 инструкций] — вычисления с числами с двойной точностью, введен с Pentium4 (предполагалось после внедрения этого набора отказаться от MMX).
  4. SSE3 [13 инструкций] — добавлена функция преобразования типа (плавающая точка→целое).
  5. SSSE3 [16 инструкций + SSE3] — функции работы с упакованными целыми числами.
  6. SSE4 [54 инструкции. Правда, тут все сложнее, чем кажется, так как не все команды из SSE4 доступны на всех процессорах с SSE4 - существуют SSE4.1 для ядер Penryn и SSE4.2 для ядер Nehalem].
  7. SSE5 непонятная AMD'шная разработка.
  8. VT-x и AMD-V - поддержка виртуализации.
MMX и SSEn наборы инструкций введены для того, чтобы было проще работать с длинными числами (128бит в SSEn или 64бит в MMX). Необходимость наличия MMX на x64 машине остается под вопросом.

Что-то еще?

Предсказатель переходов анализирует историю совершенных переходов и в зависимости от результатов запрашивает подгрузку в кэш новых данных.
Другой не менее масштабное дополнение - hyper-threading — гипер(много-)поточность. Когда физическое ядро процессора стопориться (происходит ошибка системы предсказания переходов, точность работы которой около 90%, или обращение к данным еще не подгруженным в кэш-память), сменяется набор регистров и начинает работать второе логическое ядро, до тех пор, пока первое физическое ядро не сможет продолжить работу (то есть пока не будет устранена причина ступора).
Сокет — это тип разъема, используемый для подключения процессора. Сейчас они все многоногие и ужасные (для самой распространенной архитектуры PC-совместимых компьютеров). Однако сокеты от фирмы AMD (для своих же процессоров) гораздо дешевле, чем сокеты от фирмы intel (справедливо, что для intel'овских процессоров). Причина лежит в сложности конструкции: AMD использует просто длинные ножки, которых крайне много, но они вставляются в нормальные дырки. А Intel использует маленькие ножки на процессоре, но сложное крепление контактов на плате.
Архитектуры. Самой популярной архитектурой на стационарных компьютерах остается x86 (Intel/AMD). Почти все мобильные устройства сделаны на основе ARM процессоров. Так же существует много других архитектур: SPARC, POWER PC, полноценные компьютеры на которых почти недоступны рядовым пользователям.

Комментариев нет:

Отправить комментарий