Чому x86 потворний? Чому він вважається неповноцінним порівняно з іншими? [зачинено]


105

Нещодавно я читав деякі архіви SO і стикався з твердженнями проти архітектури x86.

та багато інших коментарів, як

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

Чи може хтось люб’язно дати мені причини вважати x86 потворним / поганим / неповноцінним порівняно з іншими.


1
Я збираюся зі S&A на основі відповідей поки що, але зазначу, що CISC не є проблемою для набору інструкцій m68k. x86 - це те, що воно є, і ви можете його зберегти.
dmckee --- кошеня колишнього модератора

що таке "S&A"? "CISC не є проблемою для набору інструкцій m68k." -- Чому ні?
кігті

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

4
+1 для дуже цікавого питання.
Повне Тюрінг

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 інструкції під назвою " micro-ops " під обкладинками, щоб зробити такі оптимізації практичними для впровадження в апаратному забезпеченні.
  4. У деяких аспектах x86 не поступається, він просто відрізняється. Наприклад, вхід / вихід обробляється як відображення пам'яті в переважній більшості архітектур, але не на x86. (Примітка. Сучасні машини 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інструкція потребує відносно великого блоку коду С для опису того, що вона робить:

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

    Це одна інструкція, що виконує навантаження, зберігає, і два додавання або віднімання (керовані введенням прапора), кожне з яких буде окремою інструкцією на машині RISC.

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

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

EDIT: Це не повинно бути ударом x86! партія. У мене було мало вибору, крім того, щоб зробити якусь суму, враховуючи спосіб постановки питання. Але за винятком (1), всі ці речі були зроблені з уважних причин (див. Коментарі). Дизайнери Intel не дурні - вони хотіли досягти деяких речей своєю архітектурою, і це деякі податки, які вони повинні були сплатити, щоб зробити ці речі реальністю.


17
Це компроміс. Міцність у тому, що двійковий розмір може бути меншим, але слабкість полягає в тому, що вам потрібно мати дуже складне обладнання, щоб реалізувати аналізатор цих інструкцій. Переважна більшість інструкцій все одно мають однаковий розмір - більшість причин для опкодів змінної довжини на x86 полягає в тому, коли вони вирішили додати функції і виявили, що не можуть представити те, що хочуть, у кількості бітів, з якими їм довелося працювати. . Переважна більшість людей не стосується двійкового розміру майже настільки ж, як складність обладнання або енергоспоживання.
Біллі ONeal

8
@Joey Adams: Контрастуйте інструкції змінної довжини x86 із режимом великого пальця ( en.wikipedia.org/wiki/ARM_architecture#Thumb ). Режим великого пальця призводить до значно меншого об'єктного коду для ARM, оскільки короткі інструкції відображаються безпосередньо у звичайних інструкціях. Але оскільки існує велике зіставлення 1: 1 між більш великими інструкціями та меншими, обладнання для розбору легко реалізувати. Інструкції змінної довжини x86 не мають цих переваг, оскільки вони не були розроблені таким чином.
Біллі ONeal

7
(6) Не кожен оп-код повинен використовуватися кожною програмою, але чорт, коли мені потрібен SSE3, я радий, що він є.
Кріс К

4
@Chris Kaminski: Як це не впливає на обладнання? Звичайно, на сучасному повнорозмірному комп’ютері ніхто не піде на опіку, але якщо я роблю щось на зразок мобільного телефону, я дбаю більше про споживання енергії, ніж майже про все інше. Опкоди змінної довжини не збільшують час виконання, але обладнання для декодування все ще потребує енергії для роботи.
Біллі ONeal

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

25

Головний стукіт проти x86 в моєму розумі - це його джерела CISC - набір інструкцій містить безліч неявних взаємозалежностей. Ці взаємозалежності ускладнюють виконання таких завдань, як переупорядкування інструкцій на мікросхемі, тому що артефакти та семантика цих взаємозалежностей повинні зберігатися для кожної інструкції.

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

У архітектурі RISC інструкція add вказуватиме вхідні операнди та регістри виводу, і все про операцію відбуватиметься з використанням лише цих регістрів. Це набагато простіше роз'єднати додавання операцій, які знаходяться поруч один з одним, оскільки немає реєстрації прапорів 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, тому не можу його критикувати.
Дторп

4
Я не думаю, що ця відповідь є достатньо поганою, щоб сказати, але я думаю, що весь аргумент "RISC менший і швидший, ніж CISC", не є актуальним в сучасну епоху. Звичайно, AXP, можливо, був набагато швидшим за свій час, але справа в тому, що сучасні RISC та сучасні CISC є приблизно однаковими, що стосується продуктивності. Як я вже говорив у своїй відповіді, незначне покарання потужності для декодування x86 є причиною не використовувати x86 для чогось типу мобільного телефону, але це мало аргументів для повнорозмірного робочого столу чи ноутбука.
Біллі ONeal

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 за єдину відповідь тут від того, хто насправді має історичне підґрунтя щодо цього питання.
Біллі ONeal

3
Пам'ять завжди була повільною. Це можливо (відносно кажучи) сьогодні повільніше, ніж це було тоді, коли я почав із Z80-х та CP / M у 1982 році. Вимирання - це не єдиний шлях еволюції, оскільки із вимиранням цей конкретний еволюційний напрям припиняється. Я б сказав, що x86 добре адаптувався за 28 років (поки що існує).
Олоф Форшелл

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 буде містити решту.

Процесор 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 кращим кандидатом для використання чистого RTOS.

На більш особистій ноті мені складніше написати збірку RISC, ніж x86. Я вирішую це, записуючи процедуру RISC в C, компілюючи та змінюючи створений код. Це більш ефективно з точки зору виробництва коду і, ймовірно, менш ефективно з точки зору виконання. Усі ці 32 регістри, які слід вести. З x86 - навпаки: 6-8 регістрів з "справжніми" іменами робить проблему більш керованою і вселяє більше впевненості, що створений код буде працювати, як очікувалося.

Потворний? Це на очах у глядача. Я віддаю перевагу "іншим".


a, b і c у моїх прикладах слід розглядати як змінні на основі пам'яті, а не на безпосередні значення.
Олоф Форшелл

... "dword ptr" використовується для вказівки розміру змінної, розмір якої невідомий, якщо, наприклад, вона просто оголошена зовнішньою або якщо ви ліниві.
Олоф Форшелл

2
Це не перший раз, коли я почув пропозицію спершу написати це на C, а потім перегнати його в асемблер. Це безумовно допомагає
Джо Плант

У перші дні всі процесори були RISC. CISC розроблений як стратегія пом'якшення стану систем пам'яті чорного ядра, які були ДУЖЕ повільними, таким чином CISC, маючи меншу кількість потужних інструкцій, ставив менше навантаження на підсистему пам'яті і краще використовував пропускну здатність. Крім того, спочатку регістри розглядалися як мікросхеми, в пам'яті CPU, для накопичення. Востаннє, коли я серйозно орієнтувався на машину RISC, був 1993 рік - SPARC та HP Prisim. SPARC був жахливим на всій плані. Prisim був до 20 разів таким же швидким, як 486 на add / sub / mul, але всмоктував трансценденталі. CISC краще.

@OlofForshell Ви кажете, there typically won't be a reminderале у wiki йдеться про те, що мипи мають це: en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Олексій Жуковський

10

Я думаю, що це питання має помилкове припущення. В основному це просто одержимі RISC вчені, які називають x86 потворним. Насправді, ISA x86 може виконувати в одній інструкції операцію, яка б зайняла 5-6 інструкцій щодо ISA RISC. Вентилятори 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 СТОП ДОПОМОГА ВІД

1
Я думаю, що Intel зменшив швидкість процесора та менші розміри штампів значною мірою усунув перепад потужності. Новий подвійний 64-розрядний процесор Celeron з 64 кт L1 та 1 МБ кеш-пам'яті L2 - це 7,5 Вт чіп. Це моя "Starbucks" машина для тусовок, а термін служби акумулятора смішно довгий, і вона буде обертатися навколо машини P6. Як хлопець, що займається в основному обчисленнями з плаваючою точкою, я давно віддав RISC. Це просто повзає. Зокрема, SPARC був жорстоко льодовиковим. Ідеальним прикладом того, чому RISC смокче, став процесор Intel i860. Intel більше ніколи не пішла ТУТ.

@RocketRoy: 7,5 Вт не дуже прийнятний для пристрою, який працює 24/7 (і не виконує корисні обчислення весь час) або розряджає акумулятор 3,7 В / 2000 мАг.
R .. GitHub СТОП ДОПОМОГА ВІД

2
@RocketRoy "Процесор Intel i860. Intel більше ніколи не йшов ТУТ." Після невеликого дослідження i860 дуже схоже на Itanium: VLIW, упорядкований компілятором паралелізм інструкцій ....
Jonathon Reinhart,

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-бітовому коді, використовуючи спеціальний префікс і навпаки.
фуз

@FUZxxl: Так ... я, певно, мав би згадати, що потворність здебільшого обмежена 16-бітовим кодом. Виправлено (я думаю). :)
cHao

Виявлена ​​неелегантність здебільшого випливає з омани, що регістри 8086 - це регістри загального призначення; це неправильно. Кожен з них має спеціальне призначення, і якщо ви не будете дотримуватися їх цілей, вам буде погано провести час.
fuz

3

Я не фахівець, але здається, що багато можливостей, чому люди не люблять це, можуть бути причинами, коли він працює добре. Кілька років тому наявність регістрів (замість стека), кадри реєстрів тощо розглядалися як приємні рішення для того, щоб зробити архітектуру людиною простішою. Однак сьогодні важлива ефективність кешу, і слова змінної довжини x86 дозволяють йому зберігати більше інструкцій у кеші. "Декодування інструкцій", на яке я вважаю, що опоненти зазначали, що колись зайняло половину чіпа, вже майже не так багато.

Я думаю, що паралелізм є одним з найважливіших чинників в даний час - принаймні для алгоритмів, які вже працюють досить швидко, щоб бути корисними. Висловлення високого паралелізму в програмному забезпеченні дозволяє апаратним засобам амортизувати (або часто повністю приховувати) затримки пам’яті. Звичайно, майбутнє архітектурного майбутнього, ймовірно, є чимось на кшталт квантових обчислень.

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


9
RISC не розроблявся з урахуванням людських розробників. Одна з ідей RISC полягала в тому, щоб перекласти частину складності чіпа на того, хто написав збірку, в ідеалі - компілятора. Більше регістрів означало менше використання пам’яті та меншу кількість залежностей між інструкціями, що дозволяє глибшими трубопроводами та підвищувати продуктивність. Зауважте, що x86-64 має вдвічі більше загальних регістрів, ніж x86, і тільки це відповідає за значні підвищення продуктивності. І інструкції щодо більшості чіпів x86 декодуються перед тим, як вони кешовані, а не після (розмір тут не має значення).
Дітріх Епп

3
@Dietrich Epp: Це не зовсім так. У x86-64 є більше реєстрів, видимих ​​в ISA, але сучасні x86 реалізації зазвичай мають файл реєстру в стилі RISC, який запитується на регістри ISA на вимогу, щоб прискорити виконання.
Біллі ONeal

"Я чув від nVidia, що однією з помилок Intel було те, що вони тримали бінарні формати близько до апаратних засобів". - Я не отримав цього і частини PTX CUDA.
кігті

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 можливо ....
Біллі ONeal

@Billy: x86 вже майже назавжди. Свого часу MIPS був конкурентом x86. Як я пам’ятаю, у x86 було вимкнено роботу, щоб досягти рівня, на якому вона була конкурентоспроможною MIPS. (Ще коли МІПС і СПАРК боролися з ним на арені робочих станцій.)
Шеннон Северанс

@Shannon Severance: Просто те, що колись щось було, не означає щось таке.
Біллі ONeal

2
@supercat: те, що люди в епоху плоскої моделі пам'яті x86-32, як правило, забувають, це те, що 16 біт означає 64 кб пам'яті (кожен, хто заважає робити математику, зрозуміє, що магія не можлива, що 8086 не був бридке покарання для підозрілих програмістів). Є кілька способів обійти 64k, але рішення 8086 було гарним компромісом.
Олоф Форшелл

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

3

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

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

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


m68k набагато смішніший і приємний людям набагато більше, ніж x86 (що не може здатися настільки "людським" для багатьох програмістів m68k), якщо правильний PoV - це те, як людина може писати код у цих зборах.
ShinTakezou

Сегмент: офсетна адресація була спробою залишатися певною мірою сумісною зі світом CP / M. Одне з найгірших рішень коли-небудь.
Повне Тюрінг

@Turing Complete: segment: offset НЕ передусім спробою залишатися сумісною зі світом CP / M. Це була дуже вдала спроба дозволити 16-бітовому процесору звертатися до понад 64 Кбайт шляхом розміщення коду, даних, стека та інших областей пам'яті в різних сегментах.
Олоф Форшелл

1
Насправді розміщення даних та стеків у різних сегментах було абсолютно марним для C; він був корисним лише для асм. У C вказівник може вказувати на дані зі статичною, автоматичною або динамічно розподіленою тривалістю зберігання, тому немає можливості відхилити сегмент. Можливо, це було корисним для Паскаля чи Фортрана чи що-небудь, але не для C, яке вже було домінуючою мовою у той час ...
R .. GitHub СТОП ДОПОМОГА ВІД

2
@Bernd: Причина fs / g була обрана для локального зберігання потоків не в тому, що регістри сегментів хороші для цього. Просто x86 серйозно голодує за регістри, а сегментні регістри не використовуються. Регістр загального призначення, що вказує на структуру потоку, працював би так само добре, і насправді багато RISC-системи з більшою кількістю регістрів використовують один в якості вказівника потоку.
R .. GitHub СТОП ДОПОМОГАТИ

1
  1. x86 має дуже обмежений набір регістрів загального призначення

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

  3. Intel прийняла жахливе рішення ввести просто дурний сегмент / компенсацію - модель, що займається пам'яттю, щоб залишатися сумісною з (на даний момент вже!) Застарілою технологією

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


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

Уявіть таку ситуацію, яку ми мали на початку 90-х (основна!):

а) Операційна система, яка мав шалені обмеження з застарілих причин (640 кБ легкодоступної оперативної пам’яті) - DOS

b) Розширення операційної системи (Windows), яке могло б зробити більше в плані оперативної пам’яті, але було обмежене, коли мова зайшла про такі речі, як ігри тощо, і не була найбільш стабільною справою на Землі (на щастя, це змінилося пізніше, але я тут я говорю про початок 90-х)

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

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

д) Але з точки зору апаратури у нас було 32-бітні машини з досить великою кількістю мегабайт оперативної пам’яті та VGA-карт з підтримкою до 1024x768

Причина такої поганої ситуації?

Просте дизайнерське рішення від Intel. Сумісність машинних інструкцій (НЕ бінарний рівень!) До чогось, що вже вмирало, я думаю, це був 8085. Інші, здавалося б, непов'язані проблеми (графічні режими тощо) були пов'язані з технічних причин і через дуже вузьку Орієнтована архітектура платформа x86 принесла із собою.

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


Єдиними основними проблемами сегментованої архітектури 8086 були те, що існував лише один не виділений сегментний регістр (ES), і що мови програмування не були розроблені для ефективної роботи з ним. Стиль масштабованого адресації, який він використовує, буде дуже добре працювати на об'єктно-орієнтованій мові, яка не очікує, що об’єкти зможуть запускатися за довільними адресами (якщо вирівнювати об'єкти за межами абзацу, посилання на об'єкти повинні мати лише два байти, а не чотири). Якщо порівнювати ранній код Macintosh з кодом PC, 8086 на насправді виглядає досить добре по порівнянні з 68000.
SUPERCAT

@supercat: фактично, регістр es WAS був присвячений чомусь, а саме тим строковим інструкціям, які потребували зберігання (movs, stos) або сканування (cmps та scas). З огляду на 64KiB адресацію з кожного сегменту, регістр es також надав "пропущене посилання" на пам'ять, крім коду, даних та пам'яті стека (cs, ds, ss). Сегментні регістри забезпечували своєрідну схему захисту пам’яті, за якою ви не могли звертатися за межами блоків пам'яті 64Kib регістрів. Яке краще рішення ви пропонуєте, враховуючи, що 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, як я пам'ятаю.
Олоф Форшелл

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