Почему x86 уродлив? Почему он считается неполноценным по сравнению с другими? [закрыто]


105

Недавно я читал архивы SO и встречал утверждения против архитектуры x86.

и многие другие комментарии вроде

Я пробовал искать, но не нашел причин. Я не считаю x86 плохим, вероятно, потому что это единственная архитектура, с которой я знаком.

Может ли кто-нибудь любезно дать мне основания считать x86 уродливым / плохим / неполноценным по сравнению с другими.


1
Я выберу S&A на основе полученных ответов, но попутно отмечу, что CISC не является проблемой для набора инструкций m68k. x86 - это то, что есть, и вы можете оставить его себе.
dmckee --- котенок экс-модератора

что такое «S&A»? «CISC не проблема для набора инструкций m68k». -- Почему нет?
claws

5
Микросхемы motorala серии 68000 имеют архитектуру с высокой степенью CISC, но имеют единообразный, достаточно ортогональный и очень простой набор команд. Чем отличается от x86? Я не знаю. Но обратите внимание, что существует большая разница между сложностью микросхемы и сложностью набора команд (то есть интерфейса, который видит программист на ассемблере).
dmckee --- котенок экс-модератора

4
+1 за очень интересный вопрос.
Turing Complete

1
Здесь можно найти недавнее исследование энергоэффективности различных процессоров с хорошим обсуждением того, что движет конструкциями CISC и RISC. extremetech.com/extreme/...

Ответы:


93

Пара возможных причин:

  1. x86 - относительно старый ISA (в конце концов, его прародителями были 8086)
  2. x86 значительно эволюционировал несколько раз, но для обеспечения обратной совместимости со старыми двоичными файлами требуется оборудование. Например, современное оборудование x86 по-прежнему поддерживает выполнение 16-битного кода изначально. Кроме того, существует несколько моделей адресации памяти, позволяющих старому коду взаимодействовать с одним и тем же процессором, например, реальный режим, защищенный режим, виртуальный режим 8086 и длинный режим (amd64). Некоторых это может сбивать с толку.
  3. x86 - это машина CISC. Долгое время это означало, что он был медленнее, чем RISC-машины, такие как MIPS или ARM, потому что инструкции имеют взаимозависимость данных и флаги, что затрудняет реализацию большинства форм параллелизма на уровне инструкций. Современные реализации переводят инструкции x86 в RISC-подобные инструкции, называемые « микрооперациями », чтобы сделать эти виды оптимизаций практичными для аппаратной реализации.
  4. В чем-то x86 ничем не уступает, просто он другой. Например, ввод / вывод обрабатывается как отображение памяти на подавляющем большинстве архитектур, но не на x86. (NB: современные машины x86 обычно имеют некоторую форму поддержки DMA и взаимодействуют с другим оборудованием через отображение памяти; но ISA по- прежнему имеет инструкции ввода-вывода, такие как INи OUT)
  5. В x86 ISA очень мало архитектурных регистров, что может заставить программы проходить через память чаще, чем это было бы необходимо. Дополнительные инструкции, необходимые для этого, занимают ресурсы выполнения, которые можно было бы потратить на полезную работу, хотя эффективная переадресация хранилищасохраняет низкую задержку. Современные реализации с переименованием регистров в большой физический регистровый файл могут поддерживать множество инструкций в рабочем состоянии, но отсутствие архитектурных регистров по-прежнему было значительным недостатком 32-разрядной архитектуры x86. Увеличение числа регистров x86-64 с 8 до 16 целочисленных и векторных регистров является одним из важнейших факторов того, что 64-битный код быстрее 32-битного (наряду с более эффективным ABI вызова регистров), а не увеличенной шириной каждого регистра. Некоторым могло бы помочь дальнейшее увеличение числа регистров с 16 до 32, но не в такой степени. (AVX512 действительно увеличивается до 32 векторных регистров, поскольку код с плавающей запятой имеет более высокую задержку и часто требует больше констант.) ( См. Комментарий )
  6. Ассемблерный код x86 сложен, потому что x86 - это сложная архитектура со множеством функций. Список инструкций для типичной машины MIPS помещается на листе бумаги размером с одну букву. Эквивалентный список для x86 занимает несколько страниц, а инструкции просто делают больше, поэтому вам часто требуется более подробное объяснение того, что они делают, чем может дать листинг. Например, MOVSBинструкции нужен относительно большой блок кода C, чтобы описать, что она делает:

    if (DF==0) 
      *(byte*)DI++ = *(byte*)SI++; 
    else 
      *(byte*)DI-- = *(byte*)SI--;
    

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

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

  7. X86 использует коды операций переменной длины, которые усложняют аппаратное обеспечение синтаксического анализа инструкций. В современную эпоху эта стоимость становится исчезающе маленькой, поскольку процессоры становятся все более и более ограниченными пропускной способностью памяти, чем необработанными вычислениями, но многие статьи и мнения о «битве x86» исходят из эпохи, когда эта стоимость была сравнительно намного выше.
    Обновление 2016: Anandtech опубликовал обсуждение размеров опкодов для x64 и AArch64 .

РЕДАКТИРОВАТЬ: Это не должно быть bash x86! партия. У меня не было другого выбора, кроме как нанести некоторый удар, учитывая формулировку вопроса. Но за исключением (1), все это было сделано по уважительным причинам (см. Комментарии). Дизайнеры Intel не глупы - они хотели чего-то добиться с помощью своей архитектуры, и это некоторые из налогов, которые им пришлось заплатить, чтобы воплотить эти вещи в жизнь.


17
Это компромисс. Его преимущество в том, что размер двоичного файла может быть меньше, но его слабость в том, что вам нужно очень сложное оборудование для реализации парсера для этих инструкций. Подавляющее большинство инструкций в любом случае имеют одинаковый размер - большая часть причин использования кодов операций переменной длины на x86 связана с тем, что они решили добавить функции и обнаружили, что не могут представить то, что им нужно, в количестве бит, с которыми им пришлось работать. . Подавляющее большинство людей не так сильно озабочены размером двоичного файла, как сложность оборудования или энергопотребление.
Билли Онил

8
@Joey Adams: сравните инструкции переменной длины x86 с режимом большого пальца ARM ( en.wikipedia.org/wiki/ARM_architecture#Thumb ). Режим Thumb Mode приводит к значительно меньшему объему объектного кода для ARM, поскольку более короткие инструкции отображаются непосредственно на обычные инструкции. Но поскольку существует отображение 1: 1 между большими инструкциями и меньшими, аппаратное обеспечение синтаксического анализа просто реализовать. Инструкции переменной длины x86 не имеют этих преимуществ, потому что они изначально не были разработаны таким образом.
Билли Онил

7
(6) Не каждый код операции должен использоваться каждой программой, но, черт возьми, когда мне нужен SSE3, я рад, что он у меня есть.
Крис К.

4
@Chris Kaminski: Как это не влияет на оборудование? Конечно, на современном полноразмерном компьютере никого не волнует, но если я делаю что-то вроде сотового телефона, меня больше заботит энергопотребление, чем что-либо еще. Коды операций переменной длины не увеличивают время выполнения, но аппаратное обеспечение декодирования по-прежнему требует питания для работы.
Билли Онил

5
Это одна из вещей, которые делают набор инструкций x86 таким уродливым, поскольку он не может решить, является ли это аккумулятором или архитектурой на основе регистрового файла (хотя это в основном было исправлено в 386, что сделало набор инструкций намного более ортогональным. , независимо от того, что вам говорят фанаты 68k).
ninjalj

25

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

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

В архитектуре RISC инструкция добавления будет определять входные операнды и выходные регистры, и все, что касается операции, будет происходить с использованием только этих регистров. Это значительно упрощает разделение операций добавления, которые находятся рядом друг с другом, потому что нет регистра флагов bloomin, заставляющего все выстраиваться в линию и выполнять один файл.

Микросхема DEC Alpha AXP, выполненная в стиле RISC в стиле MIPS, была болезненно спартанской в ​​доступных инструкциях, но набор инструкций был разработан так, чтобы избежать неявных зависимостей регистров между инструкциями. Не было аппаратного регистра стека. Регистр аппаратно определяемых флагов отсутствовал. Даже указатель инструкции был определен ОС - если вы хотели вернуться к вызывающей стороне, вы должны были решить, как вызывающая сторона собиралась сообщить вам, по какому адресу вернуться. Обычно это определялось соглашением о вызовах ОС. Однако на x86 это определяется аппаратным обеспечением чипа.

В любом случае, за 3 или 4 поколения микросхем Alpha AXP аппаратное обеспечение превратилось из буквальной реализации спартанского набора инструкций с 32 регистрами int и 32 регистрами с плавающей запятой в механизм массового неупорядоченного выполнения с 80 внутренними регистрами, переименованием регистров и т.д. пересылка результатов (где результат предыдущей инструкции перенаправляется более поздней инструкции, которая зависит от значения) и всевозможные дикие и сумасшедшие бустеры производительности. И, несмотря на все эти навороты, кристалл чипа AXP был все еще значительно меньше, чем сопоставимый кристалл чипа Pentium того времени, а AXP был чертовски быстрее.

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

Я написал много ассемблера x86 и могу полностью оценить удобство его корней CISC. Но я не осознавал, насколько сложна x86, пока не потратил некоторое время на написание ассемблера Alpha AXP. Я был потрясен простотой и единообразием AXP. Различия огромны и глубоки.


6
Я не стану слушать крики CISC как таковых, пока вы не объясните m68k.
dmckee --- котенок экс-модератора

2
Я не знаком с m68k, поэтому не могу его критиковать.
dthorpe

4
Я не думаю, что этот ответ достаточно плох, чтобы голосовать против, но я действительно думаю, что весь аргумент «RISC меньше и быстрее, чем CISC» не совсем актуален в современную эпоху. Конечно, для своего времени AXP мог бы быть намного быстрее, но факт в том, что современные RISC и современные CISC примерно одинаковы, когда дело касается производительности. Как я сказал в своем ответе, небольшое снижение мощности для декодирования x86 является причиной не использовать x86 для чего-то вроде мобильного телефона, но это небольшой аргумент в пользу полноразмерного настольного компьютера или ноутбука.
Билли Онил

4
@Billy: размер - это больше, чем просто размер кода или размер инструкции. Intel платит значительный штраф за площадь поверхности чипа, чтобы реализовать аппаратную логику для всех этих специальных инструкций, будь то ядро ​​микрокода RISC под капотом или нет. Размер матрицы напрямую влияет на стоимость производства, поэтому он по-прежнему актуален при проектировании современных систем.
dthorpe

1
@dthorpe: Я не согласен с большинством, если не со всем, что вы написали. Начиная с 8086, вам не нужно было беспокоиться о том, безопасно ли выполнить один addза другим add. Правила ясны. Вам также не нужно заниматься переупорядочиванием инструкций. Начиная с Pentium Pro в середине 90-х, ЦП делает это за вас. То, о чем вы говорите, могло быть проблемой 20 лет назад, но я не вижу причин противопоставлять это архитектуре x86 в настоящее время.
Натан Феллман

21

Архитектура x86 восходит к дизайну микропроцессора 8008 и его родственников. Эти процессоры были разработаны в то время, когда память была медленной, и если вы могли сделать это на кристалле процессора, он часто был намного быстрее. Однако место на кристалле ЦП также было дорогим. Эти две причины заключаются в том, что существует лишь небольшое количество регистров, которые, как правило, имеют специальное назначение, и сложный набор инструкций со всеми видами ошибок и ограничений.

Другие процессоры той же эпохи (например, семейство 6502) также имеют аналогичные ограничения и особенности. Интересно, что и серия 8008, и серия 6502 предназначались как встраиваемые контроллеры. Уже тогда ожидалось, что встроенные контроллеры будут программироваться на ассемблере и во многом ориентированы на программиста сборки, а не на автора компилятора. (Посмотрите на микросхему VAX, чтобы узнать, что происходит, когда вы обслуживаете компилятор.) Разработчики не ожидали, что они станут вычислительными платформами общего назначения; вот для чего были нужны вещи, подобные предшественникам архива POWER. Революция домашних компьютеров, конечно, изменила это.


4
+1 за единственный ответ здесь от человека, который, кажется, действительно имеет историческое прошлое по этому вопросу.
Билли Онил

3
Память всегда была медленной. Возможно (условно говоря) сегодня медленнее, чем когда я начал с Z80s и CP / M в 1982 году. Вымирание - не единственный путь эволюции, потому что с вымиранием это конкретное направление эволюции прекращается. Я бы сказал, что x86 хорошо адаптировалась за 28 лет своего существования (до сих пор).
Olof Forshell 07

4
Скорость памяти на короткое время приблизилась к паритету с процессорами времен 8086. 9900 от Texas Instruments имеет дизайн, который работает только потому, что это произошло. Но затем ЦП снова вырвался вперед и остался там. Только сейчас есть тайники, которые помогут с этим справиться.
staticsan

3
@Olof Forshell: Он был совместим с ассемблером в том смысле, что ассемблерный код 8080 мог переводиться в код 8086. С этой точки зрения это 8080 плюс расширения, так же как вы могли бы рассматривать 8080 как 8008 плюс расширения.
Дэвид Торнли

3
@Olof Forshell: За исключением того, что 8086 был разработан для этого. Это было расширение 8080, и большинство (возможно, все) инструкций 8080 отображались один-к-одному с явно схожей семантикой. Это не относится к архитектуре IBM 360, как бы вы ее ни продвигали.
Дэвид Торнли

13

У меня есть несколько дополнительных аспектов:

Представьте, что операция "a = b / c" x86 реализует это как

  mov eax,b
  xor edx,edx
  div dword ptr c
  mov a,eax

В качестве дополнительного бонуса инструкции div edx будет содержать остаток.

Процессору RISC потребуется сначала загрузить адреса b и c, загрузить b и c из памяти в регистры, выполнить деление и загрузить адрес a, а затем сохранить результат. Синтаксис dst, src:

  mov r5,addr b
  mov r5,[r5]
  mov r6,addr c
  mov r6,[r6]
  div r7,r5,r6
  mov r5,addr a
  mov [r5],r7

Здесь обычно не бывает остатка.

Если какие-либо переменные должны быть загружены через указатели, обе последовательности могут стать длиннее, хотя это менее вероятно для RISC, поскольку он может иметь один или несколько указателей, уже загруженных в другой регистр. x86 имеет меньше регистров, поэтому вероятность того, что указатель окажется в одном из них, меньше.

Плюсы и минусы:

Команды RISC могут быть смешаны с окружающим кодом для улучшения планирования команд, это менее вероятно с x86, который вместо этого выполняет эту работу (более или менее хорошо в зависимости от последовательности) внутри самого процессора. Приведенная выше последовательность RISC обычно будет иметь длину 28 байтов (7 инструкций по 32 бита / 4 байта каждая) в 32-битной архитектуре. Это заставит внешнюю память работать больше при выборке инструкций (семь выборок). Более плотная последовательность x86 содержит меньше инструкций, и, хотя их ширина варьируется, вы, вероятно, также видите в среднем 4 байта на инструкцию. Даже если у вас есть кеши инструкций для ускорения этого процесса, семь выборок означают, что вам придется восполнить дефицит трех в другом месте по сравнению с x86.

Архитектура x86 с меньшим количеством регистров для сохранения / восстановления означает, что она, вероятно, будет переключать потоки и обрабатывать прерывания быстрее, чем RISC. Для сохранения и восстановления большего количества регистров требуется больше временного пространства стека ОЗУ для прерываний и больше постоянного пространства стека для хранения состояний потоков. Эти аспекты должны сделать x86 лучшим кандидатом для запуска чистой ОСРВ.

В более личном плане мне кажется, что писать RISC-сборку труднее, чем x86. Я решаю эту проблему, написав процедуру RISC на C, скомпилировав и изменив сгенерированный код. Это более эффективно с точки зрения создания кода и, вероятно, менее эффективно с точки зрения выполнения. Все 32 регистра, которые нужно отслеживать. В x86 все наоборот: 6-8 регистров с «настоящими» именами делают проблему более управляемой и вселяют больше уверенности в том, что созданный код будет работать должным образом.

Некрасиво? Это в глазах смотрящего. Я предпочитаю «другое».


a, b и c в моих примерах следует рассматривать как переменные на основе памяти, а не как непосредственные значения.
Olof Forshell

... "dword ptr" используется для указания размера переменной, размер которой неизвестен, если, например, она просто объявлена ​​как внешняя, или если вы были ленивы.
Olof Forshell

2
Это не первый раз, когда я слышу предложение сначала написать его на C, а затем переработать в ассемблер. Это определенно помогает
Джо Плант

Вначале все процессоры были RISC. CISC возник как стратегия смягчения последствий для ОЧЕНЬ медленных систем памяти с сердечником из железа, поэтому CISC с меньшим количеством более мощных инструкций меньше нагружает подсистему памяти и лучше использует полосу пропускания. Точно так же регистры изначально задумывались как ячейки памяти в процессоре для накопления. В последний раз я серьезно тестировал RISC-машину в 1993 году - SPARC и HP Prisim. SPARC был ужасен по всем направлениям. Prisim был в 20 раз быстрее, чем 486 на add / sub / mul, но отстой на трансцендентальных. CISC лучше.

@OlofForshell Вы говорите, there typically won't be a reminderно вики говорит, что это есть у mips: en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Алекс Жуковский

10

Я думаю, что этот вопрос основан на ложном предположении. В основном просто одержимые RISC ученые называют x86 уродливым. На самом деле, x86 ISA может выполнять операции с одной инструкцией, которые потребуют 5-6 инструкций на RISC ISA. Поклонники RISC могут возразить, что современные процессоры x86 разбивают эти «сложные» инструкции на микрооперации; тем не мение:

  1. Во многих случаях это правда лишь отчасти или совсем не так. Наиболее полезными «сложными» инструкциями в x86 являются такие вещи, как mov %eax, 0x1c(%esp,%edi,4)режимы адресации, и они не разбиты на части.
  2. На современных машинах часто важнее не количество потраченных циклов (поскольку большинство задач не привязано к процессору), а влияние кода на кэш инструкций. 5-6 инструкций фиксированного размера (обычно 32-битные) будут влиять на кеш намного больше, чем одна сложная инструкция, которая редко превышает 5 байтов.

x86 действительно вобрал в себя все хорошие аспекты RISC около 10-15 лет назад, а остальные качества RISC (собственно определяющее - минимальный набор инструкций) вредны и нежелательны.

Помимо стоимости и сложности изготовления процессоров и их требований к энергии, x86 - лучший ISA . Любой, кто говорит вам обратное, позволяет идеологии или повестке дня мешать их рассуждениям.

С другой стороны, если вы ориентируетесь на встроенные устройства, где учитывается стоимость ЦП, или встроенные / мобильные устройства, где потребление энергии является главной проблемой, ARM или MIPS, вероятно, имеют больше смысла. Имейте в виду, что вам все равно придется иметь дело с дополнительным оперативной памятью и двоичным размером, необходимым для обработки кода, который легко в 3-4 раза больше, и вы не сможете приблизиться к производительности. Будет ли это иметь значение, во многом зависит от того, что вы на нем будете запускать.


3
где потребление энергии является главной проблемой, ARM или MIPS, вероятно, имеют больше смысла ... так что, если есть хотя бы один аспект, в котором ARM или MIPS имеют больше смысла, разве это не делает x86 обязательно лучшим ISA?
Шахбаз

Вот почему я квалифицировал «лучших» с учетом «помимо стоимости ... и их требований к энергии».
R .. GitHub НЕ ПОМОГАЕТ ICE

1
Я думаю, что Intel снизила частоту процессора и меньшие размеры кристаллов в значительной степени устранили разницу в мощности. Новый двойной 64-разрядный ЦП Celeron с кэшем L1 объемом 64 Кбайт и кэшем L2 объемом 1 МБ представляет собой чип мощностью 7,5 Вт. Это мой автомат для встреч в Starbucks, и время автономной работы до смешного велико, и он будет работать без перерыва в машине P6. Как парень, занимающийся в основном вычислениями с плавающей запятой, я давно отказался от RISC. Просто ползет. В частности, SPARC был ужасно ледниковым. Прекрасным примером того, почему RISC - отстой, стал процессор Intel i860. Intel больше НИКОГДА НЕ БЫЛА ТАМ.

@RocketRoy: 7,5 ватт на самом деле неприемлемо для устройства, которое работает 24/7 (и не выполняет все время полезные вычисления) или работает от батареи 3,7 В / 2000 мАч.
R .. GitHub НЕ ПОМОГАЕТ ICE

2
@RocketRoy "Процессор Intel i860. Intel НИКОГДА ТАМ НЕ БЫЛА ". После небольшого исследования i860 во многом похож на Itanium: VLIW, параллелизм инструкций, упорядоченный компилятором ....
Джонатон Рейнхарт,

9

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

Например, в 16-битных режимах адресация может показаться совершенно причудливой; есть режим адресации для [BX+SI], но не для [AX+BX]. Подобные вещи, как правило, усложняют использование регистров, так как вам нужно убедиться, что ваше значение находится в регистре, который вы можете использовать по мере необходимости.

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

Также есть остатки былых времен, когда Intel пыталась сделать x86 лучшим процессором. Инструкции длиной в пару байтов, которые выполняли задачи, которые на самом деле никто больше не выполняет, потому что они были, откровенно говоря, слишком медленными или сложными. Инструкции ENTER и LOOP для двух примеров - обратите внимание, что код фрейма стека C похож на «push ebp; mov ebp, esp», а не «enter» для большинства компиляторов.


2
Я считаю, что проблема «ввода» и «push / mov» возникла потому, что на некоторых процессорах «push / mov» быстрее. На некоторых процессорах "ввод" выполняется быстрее. Такова жизнь.
Дитрих Эпп

4
Когда меня заставили использовать машину на базе x86 и я начал смотреть на нее (имея опыт работы с m68k), я начал чувствовать, что программирование asm расстраивает, ... как если бы я изучал программирование на таком языке, как C, а затем был вынужден войти в контакт с asm ... вы "чувствуете", что теряете силу выражения, легкость, ясность, "согласованность", "интуитивность". Я уверен, что если бы я начал программирование asm с x86, я бы подумал это не так уж и плохо ... возможно ... Я также сделал MMIX и MIPS, и их "asm lang" намного лучше, чем x86 (если это правильный PoV для Q, но, возможно, это не так)
ShinTakezou

Проблема режима адресации была исправлена ​​в 80386. Только 16-битный код имеет ограниченные режимы адресации, 32-битный код намного лучше. Вы можете получить 32-битные режимы адресации в 16-битном коде с использованием специального префикса и наоборот.
fuz 09

@FUZxxl: Да ... наверное, мне следовало упомянуть, что уродство в основном ограничивается 16-битным кодом. Исправлено (думаю). :)
cHao

Воспринимаемая неэлегантность в основном возникает из-за неправильного представления о том, что регистры 8086 являются регистрами общего назначения; это неправильно. У каждого из них есть особая цель, и если вы не будете придерживаться их целей, вам будет плохо.
fuz 09

3

Я не эксперт, но мне кажется, что многие функции, которые не нравятся людям, могут быть причиной того, что он работает хорошо. Несколько лет назад наличие регистров (вместо стека), регистровых фреймов и т. Д. Рассматривалось как хорошее решение, позволяющее сделать архитектуру более простой для людей. Однако в настоящее время важна производительность кеша, и слова переменной длины x86 позволяют хранить в кеше больше инструкций. «Декодирование инструкций», на которое, как я полагаю, указали оппоненты, когда-то занимало половину чипа, уже не совсем так.

Я думаю, что параллелизм - один из наиболее важных факторов в настоящее время - по крайней мере, для алгоритмов, которые уже работают достаточно быстро, чтобы их можно было использовать. Выражение высокого параллелизма в программном обеспечении позволяет оборудованию амортизировать (или часто полностью скрывать) задержки памяти. Конечно, будущее архитектуры, вероятно, находится в чем-то вроде квантовых вычислений.

Я слышал от nVidia, что одна из ошибок Intel заключалась в том, что они хранили двоичные форматы рядом с оборудованием. PTX CUDA выполняет некоторые быстрые вычисления использования регистров (раскрашивание графиков), поэтому nVidia может использовать регистровую машину вместо стековой, но все же имеет путь обновления, который не нарушает все старое программное обеспечение.


9
RISC не был разработан для разработчиков. Одна из идей, лежащих в основе RISC, заключалась в том, чтобы переложить часть сложности чипа на того, кто написал сборку, в идеале - на компилятор. Больше регистров означало меньшее использование памяти и меньшее количество зависимостей между инструкциями, что позволяло использовать более глубокие конвейеры и повышать производительность. Обратите внимание, что x86-64 имеет вдвое больше общих регистров, чем x86, и только это обеспечивает значительный прирост производительности. И инструкции на большинстве чипов x86 декодируются до их кэширования, а не после (поэтому размер здесь не имеет значения).
Дитрих Эпп

3
@ Дитрих Эпп: Это не совсем так. У x86-64 есть больше регистров, видимых в ISA, но современные реализации x86 обычно имеют файл регистров в стиле RISC, который по запросу сопоставляется с регистрами ISA для ускорения выполнения.
Билли Онил

«Я слышал от nVidia, что одна из ошибок Intel заключалась в том, что они хранили двоичные форматы рядом с оборудованием». - Я не понял этого и части PTX CUDA.
claws

1
@Dietrech Epp: «И инструкции на большинстве чипов x86 декодируются до их кэширования, а не после». Это неправда. Они кэшируются перед декодированием. Я считаю, что у Pentium 4 был дополнительный кеш трассировки, который кешировался после декодирования, но он был прекращен.
Натан Феллман,

это неправда, новейшие процессоры «песчаного моста» используют своего рода кэш трассировки (как в Pentium 4, о, старина: D), поэтому технологии уходят и возвращаются ...
Quonux,

3

Помимо причин, о которых уже упоминалось:

  • x86-16 имел довольно странную схему адресации памяти, которая позволяла адресовать одну ячейку памяти 4096 различными способами, ограничивала оперативную память до 1 МБ и заставляла программистов иметь дело с указателями двух разных размеров. К счастью, переход на 32-битную архитектуру сделал эту функцию ненужной, но чипы x86 по-прежнему несут в себе мусор сегментных регистров.
  • Хотя это и не вина x86 сами по себе , x86 соглашению о вызовах не было стандартизировано , как MIPS был ( в основном потому , что MS-DOS не пришел с любыми компиляторами), оставив нас с беспорядком __cdecl, __stdcall, __fastcallи т.д.

Хм ... когда я думаю о конкурентах x86, я не думаю о MIPS. ARM или PowerPC может быть ....
Билли Онил

@Billy: x86 существует почти всегда. Одно время MIPS был конкурентом x86. Насколько я помню, x86 пришлось сократить свою работу, чтобы достичь уровня, позволяющего конкурировать с MIPS. (Назад, когда MIPS и SPARC боролись с этим на арене рабочих станций.)
Шеннон Северанс

@Shannon Severance: То, что когда-то было, еще не значит, что есть.
Билли Онил

2
@supercat: в эпоху плоской модели памяти x86-32 люди склонны забывать, что 16 бит означают 64 КБ памяти (любой, кто занимается математикой, поймет, что магия невозможна, что 8086 не был мерзкое наказание для ничего не подозревающих программистов). Есть несколько способов обойти 64 КБ, но решение 8086 было хорошим компромиссом.
Olof Forshell

2
@OlofForshell: Я думаю, многие оплакивали тот факт, что 8086 был не так хорош, как 68000 (у которого было линейное адресное пространство 16 МБ и четкий путь к 4 гигабайтам). Конечно, переход на 32-разрядный процессор облегчит доступ к более чем 64 КБ, но 8086 - это 16-разрядная архитектура, которая была разработана, чтобы стать шагом вперед по сравнению с 8-разрядным 8080. Я не вижу причин, по которым Intel следовало бы делать рывок. прямо из 8-битного в 32-битный.
supercat

3

Я думаю, вы получите часть ответа, если когда-нибудь попытаетесь написать компилятор, ориентированный на x86, или если вы напишете эмулятор машины x86, или даже если попытаетесь реализовать ISA в конструкции оборудования.

Хотя я так понимаю "х86 урод!" Я все еще думаю, что писать сборку x86 веселее, чем MIPS (например) - последнее просто утомительно. Это всегда должно было быть приятным для компиляторов, а не для людей. Я не уверен, что чип мог бы быть более враждебным по отношению к разработчикам компиляторов, если бы попытался ...

Самая уродливая часть для меня - это способ (в реальном режиме) работы сегментации - то, что любой физический адрес имеет 4096 псевдонимов сегмент: смещение. Когда в последний раз это было нужно ? Все было бы намного проще, если бы сегментная часть была строго старшими битами 32-битного адреса.


m68k намного смешнее и приятнее для людей, чем x86 (который не может казаться таким «человечным» многим программистам m68k), если правильный PoV - это способ, которым человек может писать код на этой сборке.
ShinTakezou

Адресация сегмента: смещение была попыткой до некоторой степени оставаться совместимой с миром CP / M. Одно из худших решений на свете.
Turing Complete

@Turing Complete: segment: offset НЕ был в первую очередь попыткой сохранить совместимость с миром CP / M. Это была очень успешная попытка разрешить 16-битному процессору адресовать более 64 Кбайт путем размещения кода, данных, стека и других областей памяти в разных сегментах.
Olof Forshell

1
На самом деле размещение данных и стека в разных сегментах было совершенно бесполезно для C; его можно было использовать только для asm. В C указатель может указывать на данные со статической, автоматической или динамически выделяемой продолжительностью хранения, поэтому нет возможности исключить сегмент. Может быть, это было полезно для Pascal или Fortran или чего-то еще, но не для C, который уже был доминирующим языком в то время ...
R .. GitHub ПРЕКРАТИТЕ ПОМОЩЬ ICE

2
@Bernd: Причина, по которой fs / gs были выбраны для локального хранилища потока, не в том, что регистры сегментов подходят для этого. Просто x86 серьезно голодала по регистрам, а сегментные регистры не использовались. Регистр общего назначения, указывающий на структуру потока, также мог бы работать, и на самом деле многие системы RISC с большим количеством регистров используют один в качестве указателя потока.
R .. GitHub НЕ ПОМОГАЕТ ICE

1
  1. x86 имеет очень и очень ограниченный набор регистров общего назначения

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

  3. Intel приняла ужасающее решение ввести явно глупую модель адресации сегмента / смещения памяти, чтобы оставаться совместимой с (уже сейчас!) Устаревшей технологией.

  4. В то время, когда все переходили на 32-разрядную версию, x86 сдерживал массовый мир ПК, будучи скудным 16-разрядным (большинство из них - 8088 - даже только с 8-разрядными внешними путями данных, что еще страшнее!).


Для меня (а я ветеран DOS, который видел каждое поколение ПК с точки зрения разработчиков!) Пункт 3. был худшим.

Представьте себе такую ​​ситуацию, которая была у нас в начале 90-х (мейнстрим!):

а) Операционная система, которая имела безумные ограничения по устаревшим причинам (640 КБ легкодоступной ОЗУ) - DOS

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

c) Большая часть программного обеспечения все еще была DOS, и нам часто приходилось создавать загрузочные диски для специального программного обеспечения, потому что был этот файл EMM386.exe, который нравился некоторым программам, а другим не нравился (особенно геймеры - а я в то время был геймером AVID - знаю, что я я говорю здесь)

г) Мы были ограничены битами MCGA 320x200x8 (ладно, было немного больше со специальными приемами, было возможно 360x480x8, но только без поддержки библиотеки времени выполнения), все остальное было беспорядочно и ужасно ("VESA" - смеется)

д) Но с точки зрения оборудования у нас были 32-битные машины с довольно большим количеством мегабайт ОЗУ и карты VGA с поддержкой разрешения до 1024x768.

Причина такой плохой ситуации?

Простое дизайнерское решение от Intel. Совместимость уровня машинных инструкций (НЕ двоичного уровня!) С чем-то, что уже умирало, я думаю, это был 8085. Другие, казалось бы, не связанные проблемы (графические режимы и т. Д.) Были связаны по техническим причинам и из-за очень узкой Архитектура, ориентированная на мыслительную деятельность, принесла с собой платформу x86.

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


Единственная серьезная проблема с сегментированной архитектурой 8086 заключалась в том, что был только один невыделенный сегментный регистр (ES), и что языки программирования не были разработаны для эффективной работы с ним. Используемый им стиль масштабированной адресации будет очень хорошо работать в объектно-ориентированном языке, который не ожидает, что объекты смогут запускаться по произвольным адресам (если кто-то выравнивает объекты по границам абзаца, ссылки на объекты должны быть только двумя байтами, а не четыре). Если сравнить ранний код Macintosh с кодом ПК, 8086 на самом деле выглядит довольно хорошо по сравнению с 68000.
supercat

@supercat: на самом деле регистр es был посвящен чему-то, а именно тем строковым инструкциям, которые требовали сохранения (movs, stos) или сканирования (cmps и scas). Учитывая 64-килобайтную адресацию из каждого сегментного регистра, es также обеспечивает «недостающую связь» с памятью, отличной от памяти кода, данных и стека (cs, ds, ss). Сегментные регистры обеспечивали своего рода схему защиты памяти, в которой нельзя было адресовать блоки памяти размером 64 Кбайт вне регистров. Какое лучшее решение вы предлагаете, учитывая, что x86 была 16-битной архитектурой и ограничениями дня литографии?
Олоф Форшелл,

@OlofForshell: ES использовался для строковых инструкций, но может использоваться как незафиксированный регистр для кода, который их не использует. Способ облегчить узкое место seg-reg, не требуя слишком много места для кода операции, - это иметь префикс "rseg", который указывал бы, что для следующей инструкции формата r / m поле "r" будет выбирать из CS / SS / DS / ES / FS / GS / ?? / ?? вместо AX / BX / CX / DX / SI / DI / SP / BP и иметь префиксы для FS / GS и инструкции для LFS и LGS (например, LDS и LES). Я не знаю, как была устроена микроархитектура 8086, но я думаю, что что-то подобное могло сработать.
supercat

@supercat: как я уже писал, «регистры es также предоставляют недостающую ссылку на память, кроме ...» Насколько я помню, Fs и GS не появлялись до 386.
Olof Forshell 05

1
@OlofForshell: Они этого не сделали, что сделало архитектуру 80286 даже хуже, чем архитектуру 8086 во многих отношениях. Я хотел сказать, что добавление еще пары сегментных регистров (или даже одного, если на то пошло) сделало бы архитектуру 8086 намного более полезной, а набор инструкций мог бы быть более чистым и полезным, если бы к сегментным регистрам можно было получить доступ во многом как к другие.
supercat 05
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.