Введение
Процессор с инструкциями, способными к многоступенчатым операциям.
Комплексный набор инструкций (CISC /sɪsk/) – это компьютерная архитектура, в которой отдельные инструкции могут выполнять несколько операций низкого уровня (таких как загрузка из памяти, арифметическая операция и сохранение в память) или способны выполнять многоступенчатые операции или использовать различные режимы адресации в рамках одной инструкции. Термин был придуман задним числом в противопоставление компьютерам с упрощенным набором инструкций (RISC) и поэтому стал своего рода собирательным термином для всего, что не является RISC. Типичным отличительным признаком является то, что большинство конструкций RISC используют единую длину инструкции для почти всех инструкций и строго разделяют инструкции загрузки и сохранения. Примеры архитектур CISC включают в себя как сложные мейнфреймы, так и простые микроконтроллеры, где операции загрузки и сохранения памяти не отделены от арифметических инструкций. Конкретные архитектуры наборов инструкций, которые ретроспективно были отнесены к CISC, включают System/360 и z/Architecture, PDP 11 и VAX, а также многие другие. Известные микропроцессоры и микроконтроллеры, которые также были обозначены как CISC во многих научных публикациях, включают семейства Motorola 6800, 6809 и 68000; Intel 8080, iAPX 432 и x86; Zilog Z80, Z8 и Z8000; National Semiconductor NS320xx; MOS Technology 6502; Intel 8051; и другие. Некоторые разработки рассматривались некоторыми авторами как пограничные случаи. Например, микроконтроллеры Microchip Technology PIC в одних кругах назывались RISC, а в других – CISC.
Стимулы и льготы
До того, как философия RISC получила широкое распространение, многие архитекторы компьютеров пытались преодолеть так называемый семантический разрыв, то есть разрабатывать наборы инструкций, которые напрямую поддерживали высокоуровневые конструкции программирования, такие как вызовы процедур, управление циклами и сложные режимы адресации, позволяя объединять доступ к структурам данных и массивам в одну инструкцию. Инструкции также обычно подвергались плотной кодировке для дальнейшего повышения плотности кода. Компактность таких наборов инструкций приводила к уменьшению размера программ и снижению числа обращений к основной памяти (которые часто были медленными), что в то время (с начала 1960-х годов и далее) обеспечивало значительную экономию на стоимости компьютерной памяти и дискового пространства, а также повышало скорость выполнения. Это также обеспечивало высокую производительность программирования даже на языке ассемблера, поскольку языки высокого уровня, такие как Fortran или Algol, не всегда были доступны или подходили для решения задач. Фактически, микропроцессоры этого типа до сих пор иногда программируются на языке ассемблера для определенных критически важных приложений.
Новые инструкции
В 1970-х годах анализ языков высокого уровня показал, что компиляторы генерируют сложный машинный код. Было установлено, что добавление новых инструкций может повысить производительность. Некоторые инструкции были добавлены, которые изначально не предназначались для использования в ассемблере, но хорошо сочетались с кодом, сгенерированным компиляторами языков высокого уровня. Компиляторы были обновлены для использования этих инструкций. Преимущества семантически насыщенных инструкций с компактным кодированием заметны и в современных процессорах, особенно в высокопроизводительном сегменте, где кэш-память является ключевым компонентом (в отличие от большинства встраиваемых систем). Это объясняется тем, что эти быстрые, но сложные и дорогие памяти по своей природе ограничены в объеме, что делает компактный код выгодным. Разумеется, фундаментальная причина их необходимости заключается в том, что основная память (то есть, современная динамическая RAM) остается медленной по сравнению с (высокопроизводительным) ядром процессора.
Проблемы проектирования
Хотя многие разработки достигли цели повышения пропускной способности при снижении стоимости и позволили выражать конструкции языков высокого уровня меньшим числом инструкций, было замечено, что это не всегда так. Например, упрощенные версии сложных архитектур (то есть использующие меньше аппаратных средств) могли приводить к ситуациям, когда производительность можно было повысить, не используя сложную инструкцию (например, вызов процедуры или инструкцию входа), а вместо этого применяя последовательность более простых инструкций. Одна из причин заключалась в том, что архитекторы (разработчики микрокода) иногда "переусложняли" инструкции ассемблера, добавляя функции, которые нельзя было эффективно реализовать на доступном базовом оборудовании. Могли возникать, например, "побочные эффекты" (помимо стандартных флагов), такие как установка регистра или ячейки памяти, которые, возможно, редко использовались; если бы это осуществлялось через обычные (не дублированные) внутренние шины или даже внешнюю шину, это требовало бы дополнительных тактов каждый раз, что было бы крайне неэффективно. Даже в сбалансированных высокопроизводительных разработках сильно закодированные и (относительно) высокоуровневые инструкции могли быть сложными для декодирования и эффективного выполнения в рамках ограниченного бюджета по транзисторам. Таким образом, такие архитектуры требовали значительных усилий от разработчика процессора в тех случаях, когда более простое, но (как правило) медленное решение, основанное на таблицах декодирования и/или последовательном микрокоде, было неприемлемо. В эпоху, когда транзисторы и другие компоненты были ограниченным ресурсом, это также оставляло меньше компонентов и меньше возможностей для других видов оптимизации производительности.
Идея RISC
Схема, выполняющая действия, определенные микрокодом во многих (но не во всех) процессорах CISC, сама по себе является процессором, во многом напоминающим по структуре очень ранние конструкции центральных процессоров. В начале 1970-х годов это породило идеи вернуться к более простым конструкциям процессоров, чтобы упростить обход без (тогда относительно больших и дорогих) таблиц ROM и/или структур PLA для последовательного выполнения и/или декодирования. Ранний (ретроспективно) процессор, классифицированный как RISC (IBM 801 из Исследовательского центра IBM Watson, середина 1970-х годов), представлял собой простое устройство с глубокой конвейерной обработкой, изначально предназначенное для использования в качестве внутреннего микрокодового ядра или движка в конструкциях CISC, но также стал процессором, который познакомил с идеей RISC несколько более широкую аудиторию. Простота и регулярность, в том числе в видимом наборе инструкций, облегчили бы реализацию перекрывающихся стадий процессора (конвейера) на уровне машинного кода (то есть на уровне, доступном компиляторам). Однако конвейерная обработка на этом уровне уже использовалась в некоторых высокопроизводительных CISC-суперкомпьютерах для сокращения времени цикла выполнения инструкций (несмотря на сложности реализации в рамках ограниченного количества компонентов и сложности разводки, достижимых в то время). Внутреннее исполнение микрокода в процессорах CISC, с другой стороны, могло быть более или менее конвейерным в зависимости от конкретной конструкции и, следовательно, более или менее соответствовать базовой структуре процессоров RISC. Суперкомпьютер CDC 6600, впервые поставленный в 1965 году, также ретроспективно описывался как RISC. Он имел архитектуру "загрузить-сохранить", которая позволяла одновременно выполнять до пяти операций загрузки и двух операций сохранения под управлением программиста. Он также имел несколько функциональных блоков, способных работать одновременно.
Суперскалярный
В более современном контексте сложное кодирование переменной длины, используемое некоторыми типичными архитектурами CISC, усложняет, но все же делает возможным создание суперскалярной реализации модели программирования CISC напрямую; хорошо известными примерами этого являются оригинальный Pentium с последовательным суперскалярным выполнением и Cyrix 6x86 с внеочередным суперскалярным выполнением. Частые обращения к памяти за операндами в типичной машине CISC могут ограничивать параллелизм на уровне инструкций, который можно извлечь из кода, хотя это в значительной степени смягчается быстрыми кэш-структурами, используемыми в современных конструкциях, а также другими мерами. Благодаря своей компактности и семантической насыщенности, средний объем работы, выполняемый на единицу машинного кода (то есть на байт или бит), выше для процессора CISC, чем для RISC, что может дать ему значительное преимущество в современной реализации на основе кэша. Транзисторы для логики, ПЛИС и микрокода больше не являются дефицитным ресурсом; сегодня только большие высокоскоростные кэш-памяти ограничены максимальным количеством транзисторов. Несмотря на сложность, количество транзисторов в декодерах CISC не растет экспоненциально, как общее количество транзисторов на процессор (большинство из которых обычно используется для кэшей). В сочетании с улучшенными инструментами и передовыми технологиями это привело к новым реализациям высококодированных конструкций переменной длины без ограничений типа "загрузить-сохранить" (то есть не RISC). Это определяет повторную реализацию старых архитектур, таких как повсеместно распространенная x86 (см. ниже), а также новые конструкции микроконтроллеров для встраиваемых систем и аналогичных применений. Сложность суперскалярного выполнения в случае современной x86 была решена путем преобразования инструкций в одну или несколько микроопераций и динамической выдачи этих микроопераций, то есть косвенного и динамического суперскалярного выполнения; Pentium Pro и AMD K5 являются ранними примерами этого. Это позволяет разместить относительно простую суперскалярную схему после (довольно сложных) декодеров (и буферов), что, можно сказать, дает лучшее из обоих миров во многих отношениях. Эта техника также используется в микропроцессорах IBM z196 и более поздних микропроцессорах z/Architecture.
Термины CISC и RISC
Термины CISC и RISC стали менее значимыми по мере дальнейшей эволюции как архитектур CISC, так и RISC и их реализаций. Первые высоко (или плотно) конвейерные реализации x86, такие как процессоры 486 от Intel, AMD, Cyrix и IBM, поддерживали все инструкции, которые поддерживали их предшественники, но достигали максимальной эффективности только на относительно простом подмножестве x86, которое лишь незначительно превосходило типичный набор инструкций RISC (то есть, без типичных ограничений RISC, связанных с командами загрузки и сохранения). Intel P5 Pentium был суперскалярной версией этих принципов. Однако современные процессоры x86 также (как правило) декодируют и разбивают инструкции на динамические последовательности микроопераций, хранящихся во внутренних буферах, что позволяет выполнять большее подмножество инструкций в конвейерном (перекрывающемся) режиме и облегчает более продвинутое извлечение параллелизма из потока кода для достижения еще более высокой производительности. Вопреки распространенным упрощениям (встречающимся даже в некоторых академических текстах), не все процессоры CISC используют микрокод или имеют "сложные" инструкции. Поскольку термин CISC стал собирательным для обозначения любой архитектуры, отличной от load-store (RISC), определяющими факторами CISC являются не количество инструкций и не сложность реализации или самих инструкций, а то, что арифметические инструкции также выполняют доступ к памяти. По сравнению с небольшим 8-битным процессором CISC, инструкция RISC для операций с плавающей запятой может быть сложной. CISC даже не обязательно должен иметь сложные режимы адресации; 32- или 64-битные процессоры RISC вполне могут иметь более сложные режимы адресации, чем небольшие 8-битные процессоры CISC. PDP 10, PDP 8, Intel 80386, Intel 4004, Motorola 68000, System z, Burroughs B5000, VAX, Zilog Z80000 и MOS Technology 6502 значительно различаются по количеству, размеру и формату инструкций, количеству, типам и размеру регистров, а также по доступным типам данных. Некоторые имеют аппаратную поддержку для операций, таких как поиск подстроки, арифметики BCD произвольной точности или трансцендентных функций, в то время как другие поддерживают только 8-битное сложение и вычитание. Но все они относятся к категории CISC, поскольку имеют инструкции "загрузить-выполнить", которые загружают и/или сохраняют содержимое памяти в тех же инструкциях, которые выполняют фактические вычисления. Например, PDP 8, имеющий всего 8 инструкций фиксированной длины и вообще не использующий микрокод, является процессором CISC из-за принципа работы его инструкций. PowerPC, который имеет более 230 инструкций (больше, чем у некоторых VAX), и сложную внутреннюю структуру, такую как переименование регистров и буфер переупорядочивания, является процессором RISC, в то время как Minimal CISC имеет 8 инструкций, но явно является процессором CISC, поскольку он объединяет доступ к памяти и вычисления в одних и тех же инструкциях.
Общие ссылки
Таненбаум, Эндрю С. (2006) Структурированная организация компьютеров, пятое издание, Pearson Education, Inc. Верхний Сэдл-Ривер, Нью-Джерси.