The post has been translated automatically. Original language: Russian
Donald Knuth's MIX has two registers that immediately stand out from the rest, A and X. Both are the size of a full machine word and are at the center of computing. Much of the arithmetic, downloads, saves, and intermediate results go through them.
There is no such center in Memora8. The processor has 32 general-purpose registers, and the arithmetic instruction directly indicates where to get both operands and where to put the result.
At first glance, these are just two different ways to organize registers. In fact, the difference is deeper: the very model of data movement within the program is changing.
Why is the battery at the center of computing
In many early computers, the battery was a natural solution. If one of the operands and the location for the result are known in advance, they do not need to be fully described each time in a machine instruction.
In MIX, this role is largely performed by the A register.
The program loads a value into it, performs an operation on it, gets a new result, and then either uses it further or stores it in memory. In some operations, X is used next to A, forming an extended workspace.
This approach fits well with an architecture where the machine instruction must remain compact and the purpose of the main registers is known in advance.
The sequence of calculations is often built around a single central value. First it gets into A, then it is transformed, after which the next step uses the result already obtained again.
This makes the movement of the data clearly visible.
Calculation as a sequential transformation
Let's imagine a simple operation: you need to add two values, then apply another action to the result.
In the battery model, it is natural to first load the first value into the main register, then perform the operation with the second one. The result remains there and becomes the initial value for the next step.
This programming method resembles sequential processing of a single operating value.
This is convenient as long as the calculation is really linear.
It becomes more difficult when several intermediate results are needed at the same time. One of them has to be temporarily saved elsewhere to free up the main register for the next operation, and then returned back.
The architecture begins to influence not only the individual team, but also the order in which the programmer decomposes the calculation.
There is no mandatory center in Memora8
In Memora8, arithmetic commands work differently.
For example, ADD gets the result register number and the numbers of the two registers with the original values. The result does not have to replace one of the operands and does not have to end up in a pre-determined location.
If there are two values in r5 and r6, their sum can be written to r7. However, the original values remain available.
The following command can use any of these three registers.
This slight difference in the instruction format greatly changes the way the program is built. Calculations stop revolving around a single mandatory register. Several intermediate results can exist simultaneously as long as the program has enough free registers.
Therefore, the Memora8 register model is not only more homogeneous. It allows you to build a calculation as a movement of values between equal cells.
You have to pay for freedom with team bits
The battery architecture has an important advantage: some information can be omitted from the instructions.
If it is known in advance that the result of an arithmetic operation will end up in A, the number of this register does not need to be encoded. If A is one of the operands at the same time, you do not need to specify its source.
Memora8 refuses such savings.
In a regular register command, you must specify a destination register and two sources. Each number takes up five bits, since you need to select one of the 32 registers.
It turns out to be a classic architectural exchange.
MIX saves space within the team due to pre-defined roles. Memora8 spends more bits explicitly specifying data, but the program gets the freedom to choose which registers are involved in the operation.
For Memora8, this choice was made possible due to the fixed 32-bit instruction format. There is enough space inside it to directly specify three registers and at the same time keep an easy way to decrypt the command.
Fewer hidden assumptions
There is another consequence.
When the command works with the accumulator implicitly, the programmer must remember the current contents of this register. The program line may not name A, but its meaning still depends on what was uploaded there before.
In Memora8, dependencies are more often visible directly in the instruction itself.
If the command reads r3 and r8, it is written in the machine code. If the result is sent to r12, this is also indicated explicitly.
Such a device is convenient not only for humans.
It is also easier for the processor itself to determine which previous results the new instruction depends on. In a pipelining machine, this is important because several commands can be at different stages of execution at the same time.
Memora8 must understand which registers the instruction is reading and which register it is going to change. Explicitly specifying the operands fits this model well.
From sequential calculation to multiple live values
The difference is especially noticeable in longer expressions.
Let's say a program needs to calculate two intermediate results separately, and then combine them.
In the battery model, one of the results often has to be temporarily removed somewhere, because the main working register is needed to calculate the second one. It can be another register, if the operation allows it to be used, or memory.
If there are a large number of general-purpose registers, both results can be stored in registers at the same time. Then the third command uses them directly as two operands.
This does not mean that Memora8 will always execute a program with fewer instructions. In other places, as we have already seen in the example of comparisons or fields of the word MIX, everything can be the other way around.
But the distribution of time values is becoming freer.
The processor provides the program not with one main working register, but with a set of equal places between which it distributes data itself.
What's left of A and X then
It would be wrong to consider A and X to be an outdated error.
For MIX, these registers are part of a very seamless architecture. They are combined with the machine word format, the command system, and the way Knuth describes algorithms. Their specialization allows some actions to be expressed compactly and makes the purpose of machine parts clearly visible.
But when creating Memora8, the task was set differently.
The processor did not need to preserve the historical shape of the battery machine. It was more important to leave a small set of clear rules suitable for a 32-bit implementation and a simple pipeline.
Therefore, the battery function itself has not disappeared.
The program still needs to store the source data and arithmetic results somewhere. It's just that now any suitable place among general-purpose registers can temporarily fulfill this role.
The accumulator has transformed from a separate architectural element into a role that the program assigns to a regular register, if necessary.
X is also becoming a common case.
A similar thing happens with X.
In MIX, it has its own architectural meaning and can work together with A in operations for which one machine word is not enough.
Memora8 does not create a separate pair of central registers just because some calculation may need more than one 32-bit value.
If a program needs to store two parts of a larger result, it can use two regular registers. The connection between them exists in the logic of the program, and not as a special property of the register device.
This principle is repeated in Memora8 quite consistently.
What can be thought of as an agreement between ordinary data is not transformed into a new hardware type, if possible.
It's not the arithmetic that's changed, but the line of responsibility.
Both MIX and Memora8 eventually perform the usual calculations: they receive numbers, convert them, and save the results.
The difference is how much of the organization of these calculations is taken over by the architecture itself.
class="paragraph"> MIX tells the programmer: here is the main register A, here is its complement X, here are the index registers, and each has its own place in the machine device.
Memora8 provides 32 registers and a small set of operations on them. The value of each register at a particular moment is determined by the program.
In the first case, the architecture sets more roles in advance.
In the second case, the architecture defines fewer roles, but requires explicit data movement.
For implementation on an FPGA, the second option turned out to be natural: identical registers, identical source and destination numbers, and one common way to record the result.
Therefore, the transition from MIX to Memora8 can be seen not only as a rejection of the battery.
This is a transition from a machine where a significant part of the order of calculations is embedded in the assignment of registers, to a machine where this order is largely described by the program itself.
A and X did not disappear because their tasks ceased to exist.
There is no need to assign these tasks to two special places inside the processor.
У MIX Дональда Кнута есть два регистра, которые сразу выделяются среди остальных, — A и X. Оба имеют размер полного машинного слова и находятся в центре вычислений. Через них проходит значительная часть арифметики, загрузок, сохранений и промежуточных результатов.
В Memora8 такого центра нет. Процессор располагает 32 регистрами общего назначения, и арифметическая команда прямо указывает, откуда взять оба операнда и куда поместить результат.
На первый взгляд это просто два разных способа организовать регистры. На деле различие глубже: меняется сама модель движения данных внутри программы.
Почему аккумулятор оказался в центре вычислений
Во многих ранних вычислительных машинах аккумулятор был естественным решением. Если один из операндов и место для результата заранее известны, их не требуется каждый раз полностью описывать в машинной команде.
У MIX эту роль во многом выполняет регистр A.
Программа загружает в него значение, выполняет над ним операцию, получает новый результат и затем либо использует его дальше, либо сохраняет в память. В некоторых операциях рядом с A используется X, образуя расширенную рабочую область.
Такой подход хорошо соответствует архитектуре, где машинная команда должна оставаться компактной, а назначение основных регистров известно заранее.
Последовательность вычислений при этом часто строится вокруг одного центрального значения. Сначала оно попадает в A, затем преобразуется, после чего следующий шаг снова использует уже полученный результат.
Это делает движение данных хорошо заметным.
Вычисление как последовательное преобразование
Представим простую операцию: нужно сложить два значения, затем применить к результату ещё одно действие.
В аккумуляторной модели естественно сначала загрузить первое значение в основной регистр, затем выполнить операцию со вторым. Полученный результат остаётся там же и становится исходным значением для следующего шага.
Такой способ программирования напоминает последовательную обработку одного рабочего значения.
Это удобно, пока вычисление действительно имеет линейный характер.
Сложнее становится тогда, когда одновременно нужны несколько промежуточных результатов. Один из них приходится временно сохранять в другом месте, чтобы освободить основной регистр для следующей операции, а затем возвращать обратно.
Архитектура начинает влиять не только на отдельную команду, но и на порядок, в котором программист раскладывает вычисление.
В Memora8 нет обязательного центра
В Memora8 арифметические команды работают иначе.
Например, ADD получает номер регистра результата и номера двух регистров с исходными значениями. Результат не обязан заменять один из операндов и не обязан попадать в заранее определённое место.
Если в r5 и r6 находятся два значения, их сумму можно записать в r7. При этом исходные значения остаются доступными.
Следующая команда может использовать любой из этих трёх регистров.
Это небольшое отличие в формате инструкции сильно меняет способ построения программы. Вычисления перестают вращаться вокруг одного обязательного регистра. Несколько промежуточных результатов могут существовать одновременно, пока программе хватает свободных регистров.
Поэтому регистровая модель Memora8 не только более однородна. Она позволяет строить вычисление как движение значений между равноправными ячейками.
За свободу приходится платить битами команды
У аккумуляторной архитектуры есть важное преимущество: часть информации можно не записывать в инструкции.
Если заранее известно, что результат арифметической операции окажется в A, номер этого регистра не требуется кодировать. Если A одновременно является одним из операндов, не нужно указывать и его источник.
Memora8 отказывается от такой экономии.
В обычной регистровой команде необходимо указать регистр назначения и два источника. Каждый номер занимает пять бит, поскольку нужно выбрать один из 32 регистров.
Получается классический архитектурный обмен.
MIX экономит место внутри команды благодаря заранее установленным ролям. Memora8 тратит больше бит на явное указание данных, зато программа получает свободу выбирать, какие именно регистры участвуют в операции.
Для Memora8 такой выбор стал возможен благодаря фиксированному 32-битному формату инструкции. Внутри него достаточно места, чтобы непосредственно указать три регистра и при этом сохранить простой способ расшифровки команды.
Меньше скрытых предположений
Есть и ещё одно следствие.
Когда команда работает с аккумулятором неявно, программист должен помнить текущее содержимое этого регистра. Строка программы может не называть A, но её смысл всё равно зависит от того, что было загружено туда раньше.
В Memora8 зависимости чаще видны непосредственно в самой инструкции.
Если команда читает r3 и r8, это записано в машинном коде. Если результат отправляется в r12, это тоже указано явно.
Такое устройство удобно не только человеку.
Самому процессору также проще определить, от каких предыдущих результатов зависит новая инструкция. В конвейерной машине это важно, потому что несколько команд могут одновременно находиться на разных стадиях выполнения.
Memora8 должен понимать, какие регистры читает инструкция и какой регистр она собирается изменить. Явное указание операндов хорошо соответствует такой модели.
От последовательного вычисления к нескольким живым значениям
Различие особенно заметно в более длинных выражениях.
Допустим, программе нужно отдельно вычислить два промежуточных результата, а затем объединить их.
В аккумуляторной модели один из результатов часто приходится временно куда-то убрать, потому что основной рабочий регистр нужен для вычисления второго. Это может быть другой регистр, если операция позволяет его использовать, или память.
При наличии большого числа регистров общего назначения оба результата можно оставить в регистрах одновременно. Затем третья команда непосредственно использует их как два операнда.
Это не означает, что Memora8 всегда выполнит программу меньшим числом инструкций. В других местах, как мы уже видели на примере сравнений или полей слова MIX, всё может быть наоборот.
Но распределение временных значений становится свободнее.
Процессор предоставляет программу не один основной рабочий регистр, а набор равноправных мест, между которыми она сама распределяет данные.
Что тогда осталось от A и X
Было бы неправильно считать A и X устаревшей ошибкой.
Для MIX эти регистры являются частью очень цельной архитектуры. Они сочетаются с форматом машинного слова, системой команд и способом, которым Кнут описывает алгоритмы. Их специализация позволяет некоторым действиям выражаться компактно и делает назначение частей машины хорошо заметным.
Но при создании Memora8 задача ставилась иначе.
Процессору не требовалось сохранять историческую форму аккумуляторной машины. Важнее было оставить небольшой набор понятных правил, подходящих для 32-битной реализации и простого конвейера.
Поэтому сама функция аккумулятора никуда не исчезла.
Программе всё ещё нужно где-то хранить исходные данные и результаты арифметики. Просто теперь любое подходящее место среди регистров общего назначения может временно выполнять эту роль.
Аккумулятор из отдельного элемента архитектуры превратился в роль, которую программа при необходимости назначает обычному регистру.
X тоже становится обычным случаем
Похожее происходит и с X.
В MIX он имеет собственное архитектурное значение и может работать вместе с A в операциях, для которых одного машинного слова недостаточно.
Memora8 не создаёт отдельную пару центральных регистров только потому, что некоторому вычислению может понадобиться больше одного 32-битного значения.
Если программе требуется хранить две части более крупного результата, она может использовать два обычных регистра. Связь между ними существует в логике программы, а не как особое свойство регистрового устройства.
Этот принцип повторяется в Memora8 довольно последовательно.
То, что можно представить как соглашение между обычными данными, по возможности не превращается в новый аппаратный тип.
Изменилась не арифметика, а граница ответственности
И MIX, и Memora8 в конечном счёте выполняют обычные вычисления: получают числа, преобразуют их и сохраняют результаты.
Разница состоит в том, какую часть организации этих вычислений берёт на себя сама архитектура.
MIX говорит программисту: вот основной регистр A, вот дополняющий его X, вот индексные регистры, и у каждого есть своё место в устройстве машины.
Memora8 предоставляет 32 регистра и небольшой набор операций над ними. Значение каждого регистра в конкретный момент определяет программа.
В первом случае архитектура заранее задаёт больше ролей.
Во втором случае архитектура задаёт меньше ролей, но требует явно указывать движение данных.
Для реализации на FPGA второй вариант оказался естественным: одинаковые регистры, одинаковые номера источников и назначения, один общий путь записи результата.
Поэтому переход от MIX к Memora8 можно увидеть не только как отказ от аккумулятора.
Это переход от машины, где значительная часть порядка вычислений заложена в назначение регистров, к машине, где этот порядок в большей степени описывает сама программа.
A и X не исчезли потому, что их задачи перестали существовать.
Исчезла необходимость закреплять эти задачи за двумя специальными местами внутри процессора.