Според IBM (14,4 MB, стр. 1-1) архитектурата на една изчислителна система дефинира атрибутите ѝ от гледна точка на програмиста, т.е. концептуалната структура и функционално поведение на машината, за разлика от организацията на потока от данни, логическата и физическа структура и производителността на отделните реализации на тази архитектура. (Няколко различни реализации или „микроархитектури“ могат да принадлежат на една и съща архитектура. Когато изпълнението на множество програми на различни микроархитектури дава резултатите, дефинирани от една-единствена архитектура, те се считат съвместими за тези програми.) Понятието „системна архитектура“ е идентично с понятието „система от машинни команди“ („instruction set architecture“) и се отнася не само до командите, но и до програмния модел, методите на адресация и др. характеристики на съответната системна архитектура.
Тук са разгледани целочислените операции на 22 такива архитектури (системи от команди), от които първите 6 са CISC, а останалите – RISC. Всички примерни програми на всеки асемблерен език са изпробвани със съответна тестова програма на C, откъдето се извикват. За някои това е направено на реална машина, за други – на емулатор (QEMU, GXemul, Hercules или SIMH).
Тази архитектура е най-старата от тип CISC (S/360 – 1964 г., S/370 – 1970 г., S/390 – 1990 г., S/390x или z/Architecture – 2000 г.), която още се използва и развива активно без загуба на обратна съвместимост. S/390 е последната 32-битова архитектура от тази серия. За разлика от останалите 32-битови архитектури тук адресите са само 31-битови (в S/360 и ранните S/370 – 24-битови).
Както и по-късната архитектура VAX, тук има сравнително малко команди и специализирани групи от команди за работа с пакетирани двоично-десетични числа, както и извънредно мощни специализирани команди, подпомагащи реализация на алгоритъма за сортиране чрез сливане, генериране на контролна сума, преобразуване в и от Unicode, работа с низове и др.п. Има възможност с една-единствена команда (MVC) да се копират произволен брой байтове от една област на паметта в друга, включително ако тези области се застъпват. Имената на командите са твърде къси и съкратени, което прави разтълкуването на имената им по-трудно. В сравнение с повечето 32-битови архитектури тип CISC, тук има твърде малко методи за адресация на паметта. Всъщност има само трикомпонентна адресация (база, индекс, отместване), в която някои от компонентите могат да липсват. Но отместването не може да бъде отрицателно, индексът не се мащабира и адресните регистри не се могат да се обновяват автоматично. В резултат на това, както и на факта, че командите за преходи с относителна адресация са само 32-битови (16-битови няма), плътността на кода тук е сравнително ниска и както се вижда от таблиците по-долу, за реализация на един и същ алгоритъм са необходими повече команди и размерът на машинния код се оказва по-голям, отколкото при повечето CISC-архитектури.
Може би най-интересната особеност на тази архитектура е начинът на отразяване на резултата от аритметичните и логически операции. Тук това става само в 2 бита и съответно с 4 възможни комбинации, като има отделни команди за работа с числа с и без знак. Условията се проверяват с 4-битова маска, всеки бит от която обозначава дали съответната комбинация отговаря на условието за преход или не. В документацията липсват опростени буквени мнемоники за тези маски, но за радост такива има в книгата „Assembler Language Programming for IBM z System Servers“ от Джон Ерман.
Друга интересна особеност са регистровите двойки, които се използват за 64-битовите числа при някои операции. Двойката трябва да се състои регистри с два последователни поредни номера, като първият, който съдържа старшата дума, е с четен номер, а вторият, съдържащ младшата – с нечетен. И накрая, за разлика от повечето CISC-архитектури, тук адресът на връщане се предава на извиканата подпрограма в регистър, а не чрез стека, което спестява машинни тактове, но ако от своя страна извиканата подпрограма извиква друга, то тя трябва предварително да съхрани този регистър в друг регистър или в стека.
Тази архитектура тип CISC е на първия 32-битов миникомпютър с цена под 10000 щ.д. – 7/32 на „Interdata“, както и на няколко по-късни съвместими модела (8/32 и серията 32XX). Тя е много подобна на S/390. Най-голямата разлика е в кодовете на условието. Тук има 4 флага за тях – C (пренос), V (препълване), L (по-малко от) и G (по-голямо от). За разлика от всички останали разгледани тук архитектури с програмно достъпни флагове на кода на условието, тук няма флаг Z (нула). За нулев резултат се приема такъв, в който и L, и G са нули. За съжаление липсва команда за условен преход при по-голямо след беззнаково (логическо) сравнение.
Поради необходимостта от използване на оригиналния компилатор на C за UNIX, който не поддържа 64-битови целочислени типове, функциите, които иначе трябва да връщат 64-битов резултат, го записват по подаден адрес, което добавя по две-три команди в тези функции. Но дори ако можеше да се използва поддържащият 64-битови типове GCC, пак за тази архитектура броят на необходимите за реализация на функциите команди би бил най-голям (виж таблицата по-долу). Това се обяснява с това, че няма команда за едновременно зареждане от стека в регистри на всички аргументи на функциите, а също с това, че аритметичните и логически команди са двуоперандни, а няма мощни команди за управление на цикли, макар да има команди за сложни реализирани с микрокод операции като изчисляване на контролен цикличен код и работа със свързани списъци.
Класическа 32-битова архитектура тип CISC. Има сравнително малко команди, но някои от тях са толкова мощни, че реализацията на един и същ алгоритъм може да се напише с по-малко команди, отколкото всички останали разглеждани тук CISC-архитектури. Командите и адресните режими са подбрани много сполучливо. Програмният модел е прост – 16 регистъра, 4 от които специализирани – програмен брояч, указател на стека, указател на рамката на стека и указател към аргументите, удобен, защото всички аргументи на функциите се предават само чрез стека. Недостатък спрямо другите архитектури е, че има команди за умножение с 64-битов резултат и за делене с 64-битово делимо само за числа със знак, но не и за числа без знак. За да се направи например умножение на числа без знак с 64-битов резултат, трябва да се направят корекции на старшата половина на произведението. VAX има специални команди за обработка на низове, пакетирани десетични числа и опашки, които са изключително мощни, макар и силно специализирани. Но много по-често се използват командите за обща употреба, които са малко на брой, но са много добре подбрани и изчистени до най-малката подробност. Най-голямото им предимство е абсолютната, стопроцентна ортогоналност. Всеки операнд може да бъде както регистър, така и клетка от паметта, а също и клетка от паметта с адрес в друга клетка – пълна косвена адресация. Повечето команди имат както двуоперандна, така и триоперандна разновидност, а има и такива с 4 операнда, например изключително мощната команда „ACB“, която обединява в себе си действията на три команди (три в едно) – събиране, сравнение и преход.
VAX има извънредно мощни методи за адресация и команди за цикли, както и нещо уникално – работи с 64 и дори 128-битови числа (само за прехвърляне и нулиране – АЛУ-то е 32-битово), включително 64- и 128-битови константи. Няма друга 32-битова архитектура с такива възможности. Показателно е, че макар на пръв поглед 4-те флага на регистъра за кода на условието да са както при повечето други архитектури (N, Z, V, C), при VAX след сравнение флаг N показва винаги истинския знак, дори и при препълване, а флаг V се нулира, защото понятието „препълване“ при сравнение е безсмислено. Тогава флаг N най-вероятно се получава от изключващото „ИЛИ“ между най-старшия разред на резултата и флага за препълване. (Става дума за състоянието на флаг N след сравнение; след изваждане той отразява знаковия бит като при всички архитектури с програмно достъпни флагове N, Z, V, C.)
VAX е наистина забележително постижение, с което по мнение на автора не може да се сравнява никоя друга архитектура тип CISC. Много е жалко, че още в края на XX век производството на компютри с тази архитектура беше спряно. Ако беше продължило, можеше чрез вътрешна транслация на мощните, но дълги и бавни команди до по-къси, прости и бързи команди тип RISC (подобно на подхода на Intel от „Pentium Pro“ нататък) да се получи производителност, сравнима с останалите архитектури.
WE32000 (първоначално наричана „Bellmac 32“) е архитектурата на първия в света 32-битов микропроцесор, излязъл още през 1980 г. Това е „работният кон“ на най-влиятелната операционна система в историята – „UNIX System V“, която дава началото на огромно множество „юниксоподобни“ операционни системи. За CISC-архитектура тя има достатъчен брой целочислени регистри – 16 при WE32100, а при по-новия WE32200 – 32. За разлика от последния, WE32100 не поддържа индексна адресация с мащабиране, адресация с базов и индексен регистър и адресация с автоматично обновяване на адреса, макар че поддържа мощната косвена адресация през паметта. За съжаление в тази архитектура няма умножение с 64-битово произведение и делене с 64-битово делимо. Работата с флаговете на регистъра за кода на условието и предаването на аргументите са подобни на VAX, но липсват нейните мощни команди за управление на цикли. Затова пък има микропрограмна реализация във вид на команди с неявна адресация на някои функции и части от функции на стандартната библиотека на езика C за работа с ASCIIZ-низове – „strcpy“ (като команда „STRCPY“) и „strlen“ / „strcat“ (като команда „STREND“, която намира края на низа). За разлика от VAX и M68K (виж по-долу), при операции върху байтове и полудуми не се запазват останалите по-старши битове на операнда-местоназначение. Но има специални режими за привеждане на типове, което също показва, че тази архитектура е правена с оглед на поддръжка на езика C, разработен впрочем в същата фирма – „AT&T“ – заедно с операционната система „UNIX“.
В началото на всяка функция има по една команда за зареждане на всеки регистър, в който трябва да има аргумент на функцията. Изчисляването на адресите на по-големите от байт елементи на масиви също изисква повече команди. А и асемблерът автоматично заменя някои команди с поредици от други команди и поставя тук-там команди NOP за избягване на грешки в микропроцесора, открити след пускането му в производство. Всичко това понижава плътността на кода (виж таблиците по-долу).
Тази архитектура е много подобна на VAX. Основните разлики са три – 16-те регистъра са разделени на 2 групи (8 даннови и 8 адресни), към флаговете е добавен флаг за разширение X, който съхранява стари преноси и с който работят някои команди за ротация вместо с преноса, и липсват специализираните команди за опашки и низове. Така, макар и степента на ортогоналност да е малко по-ниска, отколкото при VAX, програмирането за тази архитектура е много приятно. Макар че много персонални компютри бяха с нея (Macintosh, Amiga, Atari, SHARP и др.), нейната съдба не беше по-различна от тази на VAX. Тя просъществува още по-кратко от нея и още в средата на 90-те години на XX век беше, уви, изоставена.
Това е архитектура тип CISC. За разлика от предходните четири разгледани тук архитектури, тя все още се използва, и то изключително широко, вече няколко десетилетия. Въпреки това по мнение на автора тази архитектура е най-голямото недоразумение сред системните архитектури, скалъпено според проф. Дейвид Патерсън само за две седмици като временно решение, докато излезе iAPX-432 на Intel, но както често става, няма по-постоянно решение от временното. Тя има ниска степен на ортогоналност – много команди могат да се използват само с точно определени регистри и методи на адресация. Единствено при нея от всичките 22 разгледани тук архитектури се използва понятието „акумулатор“, което е характерно за 8-битовите микропроцесори. Тази ниска степен на ортогоналност прави програмирането за x86 подобно на бягане с препятствия, които са буквално на всяка крачка. Освен това броят на регистрите за обща употреба (доста условно понятие, защото всеки от тях е специализиран) е много малък – само 8. Този недостиг на регистри допълнително увеличава броя на необходимите за реализация на алгоритмите команди. Все пак IA-32 има мощни методи за адресация, включително трикомпонентна с мащабиране на индекса (но за разлика от VAX, WE32K и M68K, без пълна косвена адресация чрез паметта), както и мощни команди за обработка на низове, които за съжаление са и най-неортогоналните – работят с точно определени регистри и методи на адресация. Броят на командите за 40 години се удесетори, което затрудни програмистите още повече. Но защо тогава тази архитектура е толкова разпространена? По две причини – изборът на тази архитектура за IBM PC, чиято отворена спецификация позволи масово да бъде копиран по целия свят, включително и у нас, както и дългогодишното запазване на обратна съвместимост, подобно на S/360 на IBM.
Архитектура тип RISC с мощни методи за адресация с мащабиране на индекса и програмен модел с 16 регистъра почти като при VAX, което е характерно по-скоро за CISC. Това е най-използваната в момента архитектура в света, най-вече в мобилни устройства с батерийно захранване, чийто брой стана много по-голям от броя на персоналните компютри. Но не само там – вторият в света по производителност суперкомпютър в момента на писане на този текст – японският „Фугаку“, също е изграден на базата на ARM. Освен мощните методи за адресация, има още няколко причини за това, за реализацията на един и същ алгоритъм при ARM да са необходими почти толкова малко команди, колкото при VAX, и много по-малко, отколкото в x86. На първо място, командните са три- и четириоперандни. На второ място, всяка команда може да бъде условна, т.е. да се изпълнява само ако флаговете в регистъра за кода на условието са в определено състояние, установено от някоя предходна команда. На трето място, това дали дадена команда да променя тези флагове или не, може да се променя от програмиста. На четвърто място, десният операнд на много команди минава през изместващ блок, който може да го подложи на изместване или ротация, без за това да са необходими допълнителни машинни тактове. На пето място, има команди за едновременно прехвърляне на произволен набор от всички регистри, подобно на M68K. И на шесто място, ортогоналната система от команди позволява всеки регистър да се използва за произволни цели във всяка команда. За съжаление, много от така изброените особености са премахнати в 64-битовата версия на тази архитектура.
Много подобна на ARM RISC-архитектура с няколко важни различия. На първо място, плътността на кода е по-голяма поради командите с променлив размер, като най-кратките са 2 байта (при ARM за това има отделна система 16-битови команди). На второ място, целочислените регистри за обща употреба са двойно повече (32), като има и още толкова еднакво достъпни за командите специализирани регистри. На трето място, има апаратна поддръжка на цикли, като със специална команда се задава адресът на първата команда след цикъла, който започва със следващата команда след специалната, а броят итерации се задава в специализиран регистър. На четвърто място, освен че подобно на ARM има възможност почти всяка команда (без двубайтовите) да бъде условна, има мощни комбинирани команди за сравнение и разклонение, които нито използват, нито променят флаговете на регистъра за кода на условието. На пето място, има мощни команди за изчисляване на адреси чрез изместване на индекса и събиране с базовия адрес, а командите за умножение и натрупване използват специализиран акумулатор. На шесто място, няма възможност десният операнд да минава през изместващ блок, а командите за съхранение в паметта, за разлика от тези за зареждане от паметта, не могат да използват базово-индексен метод за адресация с променлив индекс, записан в регистър. Поради (или въпреки) тези различия, именно при ARC са необходими най-малко команди за решаване на примерните задачи в сравнение с другите архитектури (виж таблицата по-долу). Може само да се съжалява, че тази толкова добре проектирана архитектура не е така популярна като ARM.
Тази архитектура е малко „по-RISC“ от ARM и ARC. Има по-малко методи на адресация и повече регистри за обща употреба – 32. От тях r0 е „scratch register“ (за временни променливи), r1 стеков указател, в r3 до r10 се предават аргументи на функциите, като тези регистри могат да се използват и за локални променливи, без да се съхраняват, а повечето от останалите регистри трябва да се съхраняват в стека, което може да става с 1 команда като при ARM. Това, че за предаване на аргументите се използват цели 8 (а не 3 или 4) регистъра, преди да се наложи предаване на следващите аргументи в стека, е много удобно. Удобно е и наличието на специален регистър-брояч на цикли и команди, които го намаляват и правят преход само ако той е различен от 0, като могат да комбинират това и с други проверки на условия. Има също условен преход към подпрограма и условно връщане от подпрограма. Адресът на връщане се пази в специален регистър със същото име като при ARM (lr). За всяка адресация и разновидност на всяка команда си има отделно име и ако се броят за различни команди, общият брой на командите става сравнително голям.
Най-интересните особености са при кодовете на условията. PPC има 2 отделни регистъра за тях. В първия („Condition Register“ или CR) има битове за по-малко, по-голямо и равно, а също и бит за препълване, който, веднъж установен, се нулира само със специална команда. Във втория („Excepton Regsiter“ или XER) са записани преносът CA, същото това препълване и „нормалното“ препълване, което се изменя, когато трябва. А кога трябва? Когато иска програмистът. Има избор или командата да не обнови нито един от двата регистъра, или да обнови само единия от тях (в повечето случаи), или да обнови и двата. Сравнението бива знаково и беззнаково („аритметично“ и „логическо“), а командите за условен преход след сравнение са едни и същи за числа със знак и без знак. Т.е. истинският бит за пренос след сравнението е скрит и командите за сравнение не обновяват бита за пренос CA в XER, а само битовете за по-голямо, по-малко и равно в CR в зависимост от типа си. Това налага след някои сравнения да се добавя по 1 команда за обновяване на преноса (в случаите, когато при x86 и ARM се използва това, че командата за сравнение променя и него).
Регистърът CR е разделен на 8 еднакви полета. Всяко от тях може да запомня по 1 условие. Условията в различните полета могат да се комбинират с побитови операции. Това е направено за поддръжка на сложни условия, макар че в езика C условията се изчисляват отляво надясно и в случай на логическо „И“ при първото неизпълнено условие изчисляването на следващите се прекратява (а при „ИЛИ“ то се прекратява след първото изпълнено условие). Явно тази възможност за запомняне на повече от 1 условие е направена за някои други езици. Изобщо тази архитектура е правена с отчитане на особеностите на езиците от високо ниво.
Няма команда „mov“. Тя се емулира чрез събиране с 0. Няма команда за проверка на флага за пренос. Това налага в случаите, когато след аритметична команда се проверява за пренос, с още 1 команда да се обновяват флаговете в CR и после вече те могат да се проверят с команда за условен преход. Няма ротация през пренос. Наляво това може да стане чрез събиране на регистър сам със себе си и преноса, но надясно няма как да стане, което е много неудобно в някои случаи. Но за сметка на това има 2 изключително мощни команди, използващи възможностите на вградения „barrel shifter“ (изместващ блок), които правят ротация наляво (без пренос) на даден регистър и копират поле от битове от него в друг на същото място (т.е. на същите битове), като или нулират останалите битове, или ги оставят без промяна.
Колкото до методите за адресация на паметта, има само 2 – адресът може да е равен или на съдържанието на някой регистър плюс постоянно отместване (косвена регистрова адресация с отместване), или на сбора от съдържанието на 2 регистъра (базово-индексна адресация). Има команди, завършващи на „u“, които обновяват съдържанието на адресния регистър при косвената регистрова адресация с отместване. При това първо се изчислява адресът чрез събиране на регистъра и отместването, след това се прави достъп до паметта по този адрес и накрая, ако командата завършва с „u“, се записва така полученият адрес в адресния регистър (т.е. това е преинкрементна или предекрементна адресация). Това налага преди всеки цикъл да се прави корекция на адреса чрез изваждане от адресния регистър на отместването, за да може при първото изпълнение на командата в цикъла първият достъп да е до началния адрес на масива. Така може да се използва преинкрементна или предекрементна адресация, спестявайки 1 команда за обновяване на адреса в цикъла. (И без това се налага да се добавя 1 команда, та по-добре тя е да е извън цикъла.)
Архитектурата SPARC е още „по-RISC“ от PowerPC. Въпреки някои неудобства (липса на команди за ротация и за работа с битови полета, което увеличава малко броя на необходимите за реализацията на даден алгоритъм команди), това е важна архитектура, защото това е наследникът на първия RISC-процесор, разработен в Калифорнийския университет в Бъркли от Дейвид Патерсън. (Вторият е MIPS, който пък е наследник на разработката на Университета в Станфорд от Джон Хенеси. Именно Патерсън и Хенеси са авторите на книгите за организация и архитектура на компютъра, които се използват най-много за обучение по тези дисциплини в света.) Освен това SPARC е единственият микропроцесор, допуснат за използване в космоса от Европейската Космическа агенция. И накрая, системата от команди от известно време е свободна, т.е. няма нужда да се плаща за реализация. Съответно има доста реализации. Разработката ѝ продължава от японската фирма „Фужицу“.
В SPARC има регистър за състоянието, в който са и четирите класически бита N, Z V и C. Подобно на много други RISC, преходите в SPARC са задържани, т.е. има т.н. „branch delay slot“. За разлика от MIPS, асемблерът не може автоматично да поставя NOP, а тази задача е оставена на програмиста или компилатора, като има възможност, разбира се, вместо NOP да се постави полезна команда. При задържаните преходи е важно да се помни, че условието за изпълнение или неизпълнение на прехода се изчислява преди да бъде изпълнена следващата команда след командата за преход, но самият преход (т.е. извличането и дешифрирането на новата команда) се отлага за следващия такт след изпълнението на въпросната команда след командата за преход.
Най-характерната особеност при SPARC е т.н. „регистров прозорец“. С командата „save“ автоматично прозорецът се превърта до следващия набор от регистри, изходните регистри на извикващата програма стават входни на извикваната и се появяват нови локални регистри. Обратната команда е „restore“. Има възможност за до 8 нива с такива прозорци. Правено е изследване, че при това положение случаите на препълване на брояча на прозорците средностатистически са около 1,5%. Това препълване се обработва с програмно прекъсване, което, както и при M68K, се нарича „капан“ (trap). Чрез регистровите прозорци в повечето случаи се избягва необходимостта от съхраняване на регистри и създаване на стекова рамка. Всичко става по апаратен път за 1 такт или малко повече. Що се отнася до предаването на аргументите на функциите, SPARC заема междинно място между ARM и MIPS32, където само първите 4 думи на аргументите се предават в регистри (а останалите в стека) и PowerPC, където в регистри се предават първите 8 думи. При SPARC се предават в регистри първите 6 думи. Но за седмата и следващите думи трябва да се „превърти“ регистровият прозорец, при което указателят на стека се намалява най-малко с 96.
Някои микропроцесори с архитектура SPARC имат апаратен умножител, който умножава 32 по 32 бита само за 1 такт.
Тази „ултра-RISC“ архитектура вече е със свободна система от команди – трета такава след SPARC и RISC-V. MIPS има изключително прост и „изчистен“ дизайн. Няма програмно достъпен регистър за кода на условието (т.н. „флагов регистър“); естествено в АЛУ-то такива флагове има, но те са скрити от програмиста. Условията се проверяват само с 4 команди – една с непосредствена адресация за числа със знак (SLTI), една с непосредствена адресация на втория операнд за числа без знак (SLTIU), една за регистрова адресация за числа със знак (SLT) и една с регистрова адресация за числа без знак (SLTU). Всяка от тези 4 команди може да установява регистъра в първия операнд в 1 или 0 в зависимост от това, дали е изпълнено или неизпълнено едно единствено условие, а именно – дали числото в регистъра на втория операнд е по-малко от числото на регистъра във втория операнд или не. (Да, само „по-малко“!) След това с втора команда се проверява дали така установеният регистър е равен или не е равен на 0 и ако е изпълнено условието, се прави преход към даден адрес по етикет. А как става проверката на останалите 3 условия? С размяна на регистрите във втория и третия операнд се постига проверка за по-голямо, с инверсия на логическото условие във втората команда – за по-голямо или равно и със съчетание на размяната на регистрите в първата команда и инверсията на логическото условие на втората команда – за по-малко или равно. (При командите с непосредствена адресация на втория операнд регистри не могат да се разменят, но може просто да се промени с 1 числото за сравнение.) Всички останали команди за сравнение и преход всъщност представляват макроси, които асемблерът автоматично транслира до някаква комбинация от гореописаните 2 вида команди, а именно – команда за установяване на регистър в зависимост от отношението между две числа и команда за проверка на този регистър и преход (разклонение). Гениално и просто.
Интересна особеност на тази архитектура е и че, подобно на SPARC, всяка команда след команда за преход (разклонение) се изпълнява, независимо от това дали се извършва преходът или не. (Това се нарича задържан преход или „branch delay slot“.) По тази причина асемблерът автоматично генерира команда NOP след всяка команда за преход, за да се изпълни именно този NOP, а не командата след него, освен ако не намери подходяща команда преди прехода, която да премести на мястото на този NOP. Изобщо асемблерът на MIPS е изключително интелигентен. Например той автоматично добавя команди за проверка за нулев делител при делене и генериране на изключение в този случай. Тази интелигентност може да се изключи с директивата „.set noreorder“, но тогава програмистът трябва сам да решава какво да постави вместо NOP-а (с други думи, коя команда да премести след командата за преход), ако това изобщо е възможно. Това в някои случаи намалява броя команди в програмата, но при всички случаи затруднява четенето на кода. Затова е добре, поне докато се придобие навик за това, да се оставя асемблерът да го прави.
Във второто издание на MIPS са били добавени няколко много полезни команди за работа с битови полета и за условно прехвърляне на данни. Общият брой на командите при MIPS е по-голям заради големия брой команди за обработка на преноса при многоразрядна аритметика. Например за събиране и изваждане на 64-битови числа в MIPS трябват 4 команди вместо 2 в процесорите с програмно достъпен флаг за пренос. Същото е и при изместването на 64-битови числа. Но това е цената, която се плаща за простотата. Не случайно MIPS беше първият микропроцесор, който премина към 64 бита – радикалният начин за отърваване от проблема с преноса, защото при 64 бита вече рядко се налага да се ползва такъв. Не трябва да се забравя и че през 90-те години фирмата „Silicon Graphics“ произвеждаше мощни работни станции с MIPS, на каквито беше правена и изключително реалистичната компютърна анимация на прочутия филм на Стивън Спилбърг „Юрски парк“ („Jurassic Park“) още през 1993 г.
Тази архитектура тип RISC е изначално проектирана като свободна. В RISC-V са избегнати някои недостатъци на по-ранните архитектури. Има само 4 метода за адресация – непосредствена, регистрова, косвена регистрова с отместване и относителна. Сравнението става само с 1 команда, а не с 2, както при повечето архитектури. Няма регистър за кода на условието („флагов регистър“). 32-битовият вариант има само 47 команди, които могат да са и 16-битови, и 32-битови, т.е. да се поберат в 2 или 4 байта. Изключително изчистен дизайн, който прилича на MIPS и може би води началото си от него, но е по-опростен. Например в него няма задържани преходи, което е голямо облекчение в сравнение с MIPS. В момента много фирми проектират такива процесори. Много перспективна архитектура, но все още не е успяла да се наложи масово, защото е относително нова – предложена е през 2010 г. Според автора x86 е масовата архитектура на миналото, ARM – на настоящето, а RISC-V – на бъдещето.
Подобно на MicroBlaze (виж по-долу), това е архитектура за FPGA. Системата ѝ от команди е много близка до тази на RISC-V, а конвенцията на извикване – до тази на MIPS. Подобно на RISC-V, тук липсват задържани преходи, но за разлика от RISC-V, няма 16-битови команди – всички команди са 32-битови. Затова и плътността на кода е по-малка от тази при RISC-V, но по-голяма от тази при MIPS.
Архитектура тип RISC с дву- и трибайтови команди. Имената и действието на голяма част от командите съвпадат с тези на RISC-V и също като при нея, тук няма регистър за кода на условието. Друга прилика с RISC-V е това, че командите за сравнение и условен преход са обединени в една команда. Но за разлика от RISC-V, тук има само 16 регистъра за обща употреба и възможност за използване на регистрови прозорци подобно на SPARC. Рядко срещана особеност на тази архитектура е наличието на апаратно управлявани цикли (подобно на ARC), за управлението на които не се изразходват машинни тактове. С командата за цикъл се задават в специални регистри началният адрес на цикъла (адресът на следващата команда), крайният адрес на цикъла (с етикет, обозначаващ първата команда след цикъла) и броят итерации, равен на съдържанието на регистър с общо предназначение минус 1. Когато програмният брояч достигне крайния адрес на цикъла, ако броячът на цикъла още не е 0, процесорът автоматично го намалява с 1 и прави преход към началния адрес на цикъла. Това се извършва схемно, паралелно и независимо от работата на останалата част от процесора и затова не изисква допълнителни машинни тактове.
Типична RISC-архитектура на „Motorola“ с 32 целочислени регистъра за обща употреба и 32-битови команди. За разлика от почти всички RISC-архитектури, поддържа мощния базово-индексен метод на адресация с мащабиране на индекса. Друг интересен момент е обработката на условните преходи. Има единствена команда за сравнение, която сравнява съдържанието на 2 регистъра или на регистър с константа и установява в определено състояние 12 бита в регистър-местоназначение. Всеки от тях съответства на определено условие за преход. След това с команда за проверка на бит се избира един от тези битове (с двубуквен мнемоничен код) за проверка на съответното условие и ако той е лог. 1, се извършва преход. Има и съответната команда за проверка дали даден бит е лог. 0. Налична е и команда за условен преход, която проверява дали съдържанието на даден регистър е по-малко, по-малко или равно, равно, по-голямо или равно или по-голямо от нула. За съжаление няма команда за получаване на старшата половина на 64-битовото произведение на две 32-битови числа. За още по-голямо съжаление, тази перспективна архитектура скоро е била изоставена от „Motorola“.
Още една свободна архитектура, обявена 10 години преди RISC-V, но така и не успяла да спечели сериозна популярност. Защо? Най-вече поради сериозни недоглеждания в системата от команди. Така например, старшата дума на 64-битовите произведения е недостъпна в потребителски режим, освен ако специален бит SUMRA в регистър SR не бъде изрично установен по програмен път в лог. 1. Освен това, немалка част от кодовото пространство е прахосана за инверсни едно на друго и следователно дублиращи се сравнения, а липсват някои полезни команди като изваждане с пренос, макар да има събиране с пренос. В гореспоменатия регистър SR има битове за пренос CY и препълване OV, но резултатът от сравненията се записва в отделен флаг F, който после с отделна команда се проверява като условие за преход. Мощните команди като условното прехвърляне CMOV са твърде малко, а изместванията и ротациите не работят с преноса. Всичко това прави програмите по-дълги, както може да се види от таблицата по-долу. С бит ND на регистър CPUCFGR процесорът може да се конфигурира да има или да няма задържани преходи, което означава, че програмите, писани за различните конфигурации са несъвместими помежду си.
Също типична RISC-архитектура, но на т.н. „мек“ процесор за FPGA. Много добре подбрани команди, включително ротация през флага за пренос. Условните преходи стават с 2 команди. Първата от тях е команда за знаково (CMP) или беззнаково (CMPU) сравнение. За разлика от повечето архитектури, тя има 3 операнда. Втората от тези команди е команда за сравнение с 0 на регистъра – първи операнд на командата за сравнение, и преход в зависимост от резултата. Тази архитектура има една уникална особеност. Във въпросния регистър командата за сравнение записва разликата от сравняваните регистри, с изключение на най-старшия бит, където записва лог. 1, ако числото във втория операнд е по-голямо от това в третия, и лог. 0 в противен случай. Това води до следния „подводен камък“: при беззнаково сравнение на 0 с 0x80000000 и знаково сравнение на 0x80000000 с 0, най-старшият бит на регистъра-резултат от сравнението става 0, което води до нулиране на целия резултат, въпреки че двата операнда са различни! Затова сравнение за равенство не може да се прави с команди CMP и CMPU, а има специални команди PCMPEQ и PCMPNE, с които това може да става. Резултатът от тези команди е 0 (лъжа) или 1 (истина), който после може да бъде сравняван с 0 като условие за преход.
Още една типична RISC-архитектура. Има много мощни команди, които могат да бъдат и условни, също както при ARM, но условността тук се изразява в анулиране на следващата команда при изпълнение на условие като резултат от текущата. Има 8 (16 за 64-битовата версия) флага за пренос – по 1 за всяка тетрада битове. В първата версия команда за целочислено умножение няма. Във версия 1.1 е добавена такава (под името „умножение на числа с фиксирана запетая без знак“), която работи с регистрите за числа с плаваща запетая, в/от които могат да се прехвърлят данни само чрез паметта (стека). Освен това няма делене, а само еднобитова „стъпка“ за деление, която трябва се повтаря 32 пъти заедно с още една команда. Поради гъвкавите и мощни условни команди за реализация на даден алгоритъм са необходими сравнително малък брой команди. Но за съжаление, и PA-RISC като VAX и M68K е „мъртва“ – HP я изоставиха в полза на „Itanium“, която свой ред също изоставиха след дълга агония. Изобщо, имайки предвид не само VAX, PA-RISC и „Itanium“, но и RISC-архитектурата „Alpha“, която също изоставиха, може да се каже, че фирмата HP се специализира в „погребения“ на компютърни архитектури. Това е много жалко.
Тази RISC-архитектура на японската фирма „Хитачи“ е със силно опростени двуоперандни команди, за да могат да се поберат в 16 бита – за разлика от командите на повечето RISC-архитектури, които са 32-битови. Иначе регистрите и аритметиката са си 32-битови. Има и един-единствен флаг T, който служи ту като флаг за пренос, ту като флаг за препълване, ту като флаг за нула. Има команди за събиране и изваждане с пренос, но само те променят преноса – командите за събиране и изваждане без пренос не го променят. Така че за да се съберат или извадят 64 бита, първо трябва да се нулира T, а след това да се използва на два пъти команди за събиране или изваждане с пренос. Подобно на PA-RISC, няма команда за делене, а само за „стъпка“ за деление. Въпреки по-големия брой команди, необходими за реализацията на даден алгоритъм, поради двойно по-късите команди размерът на кода става много малък като при CISC.
Макар че и ARM има вариант с 16-битови команди, MIPS – също, RISC-V органично съчетава 32-битови с 16-битови команди, а при CRIS (виж по-долу) повечето команди са 16-битови, все пак SH-4 е единствената от разглежданите архитектури, при която всички команди са 16-битови.
Подобно на SH-4, и при тази RISC-архитектура командите са 16-битови, но има и изключения. Допускат се команди с непосредствена адресация, при които командата става 32- или дори 48-битова. Въпреки това плътността на кода е голяма като при SH-4. За разлика от много RISC-архитектури, тук условията се проверяват с „класическите“ флагове на условията – N, Z, V и C (знак, нула, препълване и пренос). Това е единствената от разгледаните тук архитектури, която, въпреки че се води от тип RISC, позволява достъп до паметта при аритметичните и логически команди. Така този иначе верен критерий за различаване на RISC от CISC вече не може да се счита за верен при всички случаи. Още едно потвърждение на известния факт, че понастоящем CISC и RISC са доста размити понятия. Друга уникална особеност е тази, че тук липсва не само трикомпонентна, но дори и двукомпонентна адресация на паметта. Всички адреси на паметта се адресират с един-единствен регистър, в който предварително може да се зареди с една-единствена команда адресът като сбор от начален адрес и мащабиран индекс. Изобщо, доста оригинална архитектура, която, уви, вече не се поддържа.
Това е RISC-архитектура на микропроцесори с разширени възможности за обработка на сигнали. Също като в CRIS, тук повечето команди са 16-битови. Проверката на условията става подобно на SH-4 с един-единствен флаг CC, който може да се присвоява на резултатите от сравненията, стойностите на битове и др. Има отделни 8 даннови и 6 адресни (указателни) регистри, подобно на M68K. Също като Xtensa поддържа апаратно управлявани цикли (виж по-горе). Но най-характерната особеност на Blackfin е синтаксисът на командите. За разлика от всички останали архитектури, тук няма разделение на мнемоничен код на командата и операнди. Повечето команди използват подобен на езика C математически синтаксис с аритметични и логически изрази. Например вместо „ADD R0,R1,R2“ се пише просто „R0 = R1 + R2;“. Като разделител на командите се използва не символ за нов ред, а точка и запетая като в езика C. Има и команди със синтаксис, подобен на извикването на функции в C – с аргументите в скоби. Това оригинално решение прави писането и особено четенето на програмите на асемблер за тази архитектура по-привично за свикналите с езиците от високо ниво.
Тази архитектура е с „много дълга дума на командата“ (VLIW). При тези RISC-архитектури много (в случая до 4) команди се групират в т.н. „широка“ команда или пакет от команди, изпълнявани едновременно. Тук степента на контрол върху процесора е максимална. Разпределението и групирането на командите, което при останалите архитектури се прави апаратно по време на изпълнението, тук се прави по време на компилирането на програмата. При писане на асемблерен език програмистът трябва да групира командите така, че в един и същи пакет само една команда да променя даден регистър. Прочитан от друга команда в пакета регистър може да бъде записван от команда в същия пакет, защото преди изпълнението командите прочитат съдържанието на регистрите, а евентуалните нови стойности се записват чак след изпълнението им. Някои команди могат да използват и резултата от други команди в същия пакет. Разклоненията стават чрез проверка на т.н. предикати, които се променят от командите за сравнение, както и чрез някои сравнения на регистър с 0. Специално тази архитектура, също като предходната, е със синтаксис, подобен на езиците от високо ниво. Друга нейна особеност е възможността да се използват регистрови двойки, което много опростява операциите с 64-битови данни.
За да сравни плътността на кода на различните архитектури, авторът написа подпрограми с различни видове алгоритми за обработка на различни данни, ръчно оптимизирани за всяка архитектура, а именно:
um64x64.s: линеен алгоритъм absdif64.s: разклонен алгоритъм sqroot64.s: цикличен алгоритъм lcmult.s: съчетание между цикличен и разклонен алгоритъм (с gcdivis.s) nsamebit.s: обработка на битове bitrev64.s: обработка на битове ucnvrf.s: анализ на непозната програма sequence.s: адресация на паметта и работа с масиви search64.s: адресация на паметта и работа с масиви binsrch.s: адресация на паметта и работа с масиви inssort.s: адресация на паметта и работа с масиви heapSort.s: адресация на паметта и работа с масиви + извикване на функция getvlq.s: работа с низове (поредици) от байтове putvlq.s: работа с низове (поредици) от байтове getipstr.s: работа със символни низове putipstr.s: работа със символни низове getmacst.s: работа със символни низове putmacst.s: работа със символни низове udiv64.s: многоразредни изчисления udiv128.s: многоразредни изчисления
В таблицата по-долу е даден броят на командите за различните подпрограми и архитектури:
S/390 ID32 VAX WE32K M68K IA-32 ARM ARC PowerPC SPARC MIPS RISC-V Nios2 Xtensa 88K OR1K µBlaze PA-RISC SH-4 CRIS Bfin Hexagon absdif64 13 24 11 21 11 7 6 7 11 8 12 12 12 13 11 14 12 6 18 11 18 6 binsrch 23 22 16 21 22 20 15 15 19 21 18 18 18 17 18 22 19 14 25 27 24 15 bitrev64 16 20 7 17 9 6 4 6 13 15 13 13 15 12 12 16 9 8 9 6 6 2 gcdivis 16 0 11 12 11 11 11 10 15 16 12 13 13 13 14 20 15 13 21 16 18 13 getipstr 15 15 9 16 15 15 11 11 13 14 14 15 14 15 14 15 14 11 17 14 15 13 getmacst 30 32 17 29 28 27 22 22 27 30 25 27 26 28 27 30 27 24 35 30 33 20 getvlq 15 13 8 10 9 11 10 10 12 12 9 11 10 11 11 11 11 8 12 11 11 10 heapSort 52 56 29 48 37 38 35 33 44 48 44 43 44 38 37 52 42 35 56 50 49 33 inssort 17 19 13 20 19 17 15 14 17 20 16 16 16 15 17 21 19 15 21 21 20 14 lcmult 7 24 5 8 9 12 5 5 6 5 6 5 5 5 5 5 5 19 18 29 14 9 nsamebit 12 14 10 11 15 6 8 8 8 11 9 10 9 11 9 11 10 9 12 13 12 6 putipstr 30 27 15 25 24 25 23 19 26 29 26 24 26 24 27 30 26 24 42 31 35 24 putmacst 24 27 12 23 18 20 16 17 19 23 20 22 22 21 20 25 22 16 29 23 23 14 putvlq 20 20 14 17 13 15 12 12 15 19 15 16 16 16 15 19 16 13 21 18 18 13 search64 14 15 12 17 17 14 12 9 14 15 12 13 12 12 14 16 14 10 13 17 16 10 sequence 9 12 7 13 8 10 7 6 10 12 10 10 10 9 10 12 11 13 13 10 10 6 sqroot64 12 18 10 18 14 12 10 10 11 12 15 16 16 16 13 14 11 9 14 15 19 8 ucnvrf 24 20 12 20 18 18 16 13 22 24 20 18 20 18 23 22 22 18 32 19 26 16 udiv128 22 49 19 41 24 27 22 17 24 28 34 31 36 32 22 30 27 22 30 31 33 13 udiv64 4 27 13 26 5 4 13 11 16 9 20 19 20 18 16 19 15 13 14 18 13 17 um64x64 21 54 31 35 16 30 12 11 15 17 25 21 21 27 60 46 15 30 23 22 24 15 ---------------------------------------------------------------------------------------------------------------------------------------------- 396 508 281 448 342 345 285 266 357 388 375 373 381 371 395 450 362 330 475 432 437 277
Както се вижда, най-малко команди за реализация на всички подпрограми са били нужни за RISC-архитектурата ARC, а най-много – за CISC-архитектурата ID32. Това опровергава разпространеното схващане, че архитектурите тип CISC постигат същия резултат с по-малко команди от тези от тип RISC. Например от двете най-използвани днес архитектури (x86 и ARM), именно за ARM, която е RISC, са били необходими значително по-малко команди за реализация на подпрограмите, отколкото за x86, която е CISC. Този парадокс е обяснен в бележките за двете архитектури по-горе.
А в следващата таблица е дадена дължината на всяка подпрограма в байтове (lcmult.s включва в себе си gcdivis.s):
S/390 ID32 VAX WE32K M68K IA-32 ARM ARC PowerPC SPARC MIPS RISC-V Nios2 Xtensa 88K OR1K µBlaze PA-RISC SH-4 CRIS Bfin Hexagon absdif64 36 66 36 56 32 14 24 24 44 32 80 38 48 36 44 56 48 24 36 22 36 24 binsrch 80 62 68 72 54 37 60 50 76 84 96 56 72 41 72 88 76 56 50 56 48 56 bitrev64 48 62 28 68 24 14 16 22 52 60 64 36 60 36 48 64 36 32 18 12 20 8 getipstr 48 38 40 52 38 25 44 36 52 56 64 40 56 38 56 60 56 48 34 32 32 44 getmacst 100 96 72 96 80 51 88 70 108 120 128 74 104 74 108 120 108 96 70 72 72 76 getvlq 52 38 32 32 28 21 40 26 48 48 48 28 40 27 44 44 44 32 24 28 24 32 heapSort 172 172 100 156 110 85 140 110 176 192 224 134 176 107 148 208 168 144 112 108 104 116 inssort 60 66 56 64 56 35 60 40 68 80 96 48 64 36 68 84 76 64 42 44 40 48 lcmult 64 58 47 72 52 41 64 46 84 84 112 48 72 49 76 100 80 128 78 98 70 84 nsamebit 32 38 32 36 42 13 32 20 32 44 48 26 36 29 36 44 40 40 24 28 28 24 putipstr 116 84 88 100 76 50 96 74 104 120 144 80 108 68 108 120 108 96 92 88 84 104 putmacst 88 82 44 80 56 41 68 60 76 92 96 62 88 56 80 100 88 64 58 48 56 56 putvlq 64 54 56 56 36 31 48 40 60 76 80 42 64 44 60 76 64 56 42 44 40 48 search64 48 42 44 52 48 31 48 26 56 60 64 38 48 28 56 64 56 40 26 36 32 44 sequence 32 28 24 36 22 17 28 18 40 48 48 24 40 20 40 48 44 56 26 20 24 24 sqroot64 36 42 36 52 40 27 40 32 44 48 80 42 60 42 52 56 44 40 28 32 44 32 ucnvrf 88 58 56 78 66 44 72 58 96 110 128 72 96 55 98 94 96 160 80 60 80 78 udiv128 80 140 64 148 66 75 88 64 96 112 176 100 144 88 88 120 108 88 60 64 88 56 udiv64 12 72 40 84 22 9 52 36 64 36 96 48 80 51 64 76 60 56 32 40 36 68 um64x64 64 136 116 128 44 47 48 42 60 68 112 70 84 71 240 184 60 120 46 44 64 52 ---------------------------------------------------------------------------------------------------------------------------------------------- 1320 1434 1069 1518 992 708 1156 894 1436 1570 1984 1106 1540 996 1586 1806 1460 1440 978 976 1022 1074
Тази таблица се различава значително от предходната. Тук най-малка дължина (и съответно най-висока плътност) на кода има при CISC-архитектурата IA-32 заради кратките команди – средно по 2 байта, макар да има и много по-дълги. Най-голяма е дължината на кода при MIPS, която е RISC с 32-битови команди, но асемблерът на някои места е добавил команди NOP, команди за проверка за нулев делител и подравняващи команди NOP, които имат машинен код на операцията 0. При подобните на MIPS архитектури RISC-V и Xtensa е постигната много по-добра плътност на кода по три основни причини – липса на задържани преходи, обединяване на проверката на условие и условния преход в една-единствена команда и наличието на команди с дължина, по-малка от 32 бита.
Не само по тази причина, но най-вече поради това, че е свободна, RISC-V, която е и най-новата от разгледаните тук 22 архитектури, наистина може да се нарече системна архитектура на бъдещето.
Листинги за горепосочените 32-битови архитектури и за някои 64-битови (S/390x, AMD64, ARM64, ARC64, PPC64, SPARC64, MIPS64, RV64, LA64, Alpha, MMIX, PA-RISC 2.0, TILE-Gx, IA-64, E2K).
Заб.: Достъпът до листингите за 32-битовите архитектури става с името и паролата на администратора на зали 401Т и 402Т.