The post has been translated automatically. Original language: Russian
Registers are located in the very center of any processor. Arithmetic commands work with them, intermediate results are transmitted through them, and addresses and values that the program needs right now are stored in them. But even such a basic part of the processor can be arranged in completely different ways.
In Donald Knuth's MIX, the purpose of many registers is embedded directly into the architecture. In Memora8, an almost opposite approach is chosen: the processor is provided with a set of identical general-purpose registers, and the distribution of roles is mainly transferred to the software.
This difference shows well how the same task is reinterpreted when moving from a learning computer to a small processor implemented on an FPGA.
Nine MIX registers, but almost each with its own role
The MIX has nine registers that are explicitly available to the program. Two of them, A and X, are the size of a complete machine word. The six index registers I1–I6 are shorter and contain two signed bytes. The separate register J also has a size of two bytes and is used primarily to store the return address during transitions. In addition, the machine's condition includes an overflow indicator and a three-state comparison indicator.
Such a device reflects well the logic of the machine itself. The A register is the main participant in arithmetic operations. X can complement it or be used instead of it. Index registers are involved in calculating addresses, and J handles transitions.
The programmer, looking at the register, already understands approximately why it exists.
This approach has a noticeable advantage: the purpose of the processor parts is clearly visible directly in its architecture. This is especially useful for a learning machine because it allows you to consistently explain how the program is executed and what role each element plays.
But specialization has a price. Different registers have different widths, different allowed operations, and different ways of using them. The machine needs separate commands to load and save A, X, index registers, and J. In the MIX command system, this specialization is directly visible: there are, for example, separate save commands STA, ST1–ST6, STX and STJ.
It turns out to be an architecture in which the register is not just a place to store a number. His name simultaneously defines a part of his behavior.
In Memora8, the register primarily stores the value
The Memora8 version in question uses 32 general-purpose registers with a width of 32 bits. They are designated from r0 to r31, and the architecture itself almost does not assign them specific roles.
The processor does not need to know which register the programmer uses for the function argument, which contains a temporary value, where the return address is located, or which values must be saved before calling another function. These rules already apply to the agreement between programs, the compiler, and the system software.
For the hardware, almost all of these values are the same.
This solution significantly changes the boundary between the processor and the program. In MIX, a significant part of the organization of computing is expressed through specialized hardware elements. In Memora8, the register part provides a more general mechanism, and specialization occurs at a higher level.
This does not mean that the roles disappear. Routines still need arguments and return values, the stack needs a pointer, and the function call needs a return address. But it is not necessary for the processor to turn each of these roles into a special type of register.
An exception that simplifies the rest of the cases
Memora8 has one register with a special behavior — r0. When reading, it always returns zero. You can write a value to it with a command, but the state of the register will not change: the next reading will give zero again.
At first glance, this violates the idea of completely identical registers. In practice, a small special case makes it possible to simplify many common operations.
If the result of the calculation is not needed, it can be sent to r0. The null value is always available without preloading the constant. A command like ADDI r0, r0, 0 does not change anything and can be used as an operation without an action.
Specialization is applied differently here than in MIX. It is not distributed among multiple registers, each of which is designed for its own task. One special register adds a universal property that can then be used by different commands.
The remaining 31 registers retain the same architectural model.
What happens to the battery
It is especially interesting to compare Memora8 with the A register in MIX.
The battery has long been the natural center of processor architecture. The operation might not explicitly specify all its sources and recipient, because it implied the participation of A. This saved space in the machine team and simplified some hardware solutions.
In MIX, the value of A is not limited to this model, but its central role is clearly visible. Knuth describes it as a full-size general-purpose register, the contents of which usually serve as an operand for arithmetic and save commands. X complements this model and can work as an extension of A.
There is no dedicated battery in Memora8. The arithmetic instruction explicitly specifies the result register and operand registers. For example, addition receives two sources and writes the result to the selected destination register.
This requires several bits inside the instruction to specify the register numbers, but it removes the tight binding of calculations to one central location.
This approach fits well with the fixed 32-bit Memora8 instruction format. The number of each register takes up five bits, which is enough to select one of the 32 registers. As a result, the same structure can be used by a large number of operations without having to introduce different rules for accumulators, indexes, and special registers.
Indexing also ceases to be a special case property.
In MIX, the six index registers exist precisely to change the address contained in the instruction. The INDEX field of the command selects the necessary register, the value of which is added to the address part and forms the valid address of the request.
This is a very natural design for the time of MIX creation. Arrays and loops require address changes, so a special hardware indexing mechanism directly solves a common programming problem.
There is no separate class of index registers in Memora8. When working with memory, the address is constructed from a regular register and the offset specified in the instruction. The same register can previously participate in arithmetic, store an intermediate value, or receive an address as a result of another calculation.
And again, the functionality does not disappear anywhere. The hardware separation of registers by profession disappears.
For a small processor, this is important not only because of the convenience of programming. A homogeneous register model means that the register reading path, operand selection, and result recording can be built around a single common mechanism.
Special registers or special agreements
This comparison clearly shows a more general architectural choice.
You can fix the assignment directly in the hardware. Then a certain register is always an index register, another one stores the return address, and the third one participates in basic arithmetic. The program gets a ready-made structure, but the processor must maintain the differences between its elements.
You can do something else and give the programs several identical resources. Then the hardware knows less, but the compiler and the calling convention must agree on how to use these resources.
Memora8 basically chooses the second option.
For example, the return address is needed for any function call. In MIX, there is a J. In Memora8, the jump command itself can write the return address to the selected regular register, and the calling convention already determines which register is usually used for this purpose.
For the program, the result is the same: after executing the function, you need to know where to return to. However, the processor architecture does not contain a separate physical type of "return register".
Simplicity here means the same rules.
One could say that Memora8 simply uses more registers than MIX, and therefore can afford to make them universal. But it's not just about quantity.
The main difference lies in the regularity.
If the operation works with Memora8 registers, in most cases it deals with identical 32-bit objects. It is not necessary to constantly take into account that one register has the length of a full word, another is shorter, the third does not contain a sign, and the fourth is intended only for a certain class of operations.
For a hardware implementation, this means fewer variations of the same action. For the compiler, there is a freer distribution of time values. For the person studying the processor, — a shorter set of rules that need to be kept in mind at the same time.
MIX solved a different problem. His specialized registers make the internal structure of computing visual and reflect the architectural approaches of his time. Knuth's register model itself explains a significant part of how a machine is supposed to be programmed.
Memora8 moves this boundary.
The processor provides 32-bit registers and simple operations on them. And the question of which value is now a pointer, a function argument, a temporary result, or a return address remains, if possible, a program question.
This is the reinterpretation of the idea of MIX. Not to abandon register roles altogether — without them it is impossible to organize a program — but to separate the logical role of a value from the physical device in which this value is stored.
It turned out to be more useful for Memora8 to have almost identical registers and a few general rules for working with them than a lot of hardware roles. This is another example of how, when switching from a Knuth architecture to a real FPGA processor, the task itself remains, but the place where it is solved changes.
Регистры находятся в самом центре любого процессора. Именно с ними работают арифметические команды, через них передаются промежуточные результаты, в них хранятся адреса и значения, необходимые программе прямо сейчас. Но даже такая базовая часть процессора может быть устроена совершенно по-разному.
В MIX Дональда Кнута назначение многих регистров заложено непосредственно в архитектуру. В Memora8 выбран почти противоположный подход: процессору предоставляется набор одинаковых регистров общего назначения, а распределение ролей в основном передаётся программному обеспечению.
Это различие хорошо показывает, как одна и та же задача переосмысливается при переходе от учебной вычислительной машины к небольшому процессору, реализуемому на FPGA.
Девять регистров MIX, но почти каждый со своей ролью
В MIX имеется девять явно доступных программе регистров. Два из них, A и X, имеют размер полного машинного слова. Шесть индексных регистров I1–I6 короче и содержат два байта со знаком. Отдельный регистр J также имеет размер двух байтов и используется прежде всего для хранения адреса возврата при переходах. Кроме них, состояние машины включает признак переполнения и трёхсостоянийный индикатор сравнения.
Такое устройство хорошо отражает логику самой машины. Регистр A — основной участник арифметических операций. X может дополнять его или использоваться вместо него. Индексные регистры участвуют в вычислении адресов, а J обслуживает переходы.
Программист, глядя на регистр, уже примерно понимает, зачем он существует.
У этого подхода есть заметное достоинство: назначение частей процессора хорошо видно непосредственно в его архитектуре. Для учебной машины это особенно полезно, потому что позволяет последовательно объяснять, как выполняется программа и какую роль играет каждый элемент.
Но специализация имеет цену. Разные регистры имеют разную ширину, разные допустимые операции и разные способы использования. Машине нужны отдельные команды для загрузки и сохранения A, X, индексных регистров и J. В системе команд MIX эта специализация видна непосредственно: существуют, например, отдельные команды сохранения STA, ST1–ST6, STX и STJ.
Получается архитектура, в которой регистр является не просто местом хранения числа. Его имя одновременно определяет часть его поведения.
В Memora8 регистр прежде всего хранит значение
В рассматриваемой версии Memora8 используются 32 регистра общего назначения шириной 32 бита. Они обозначаются от r0 до r31, и сама архитектура почти не закрепляет за ними определённых ролей.
Процессору не требуется знать, какой регистр программист использует для аргумента функции, какой содержит временное значение, где находится адрес возврата или какие значения необходимо сохранить перед вызовом другой функции. Эти правила относятся уже к соглашению между программами, компилятором и системным программным обеспечением.
Для аппаратуры почти все эти значения одинаковы.
Такое решение заметно меняет границу между процессором и программой. В MIX значительная часть организации вычислений выражена через специализированные аппаратные элементы. В Memora8 регистровая часть предоставляет более общий механизм, а специализация возникает уровнем выше.
Это не означает, что роли исчезают. Подпрограммам всё равно нужны аргументы и возвращаемые значения, стеку нужен указатель, а вызову функции — адрес возврата. Но процессору необязательно превращать каждую из этих ролей в особый тип регистра.
Исключение, которое упрощает остальные случаи
У Memora8 есть один регистр с особым поведением — r0. При чтении он всегда возвращает ноль. Записать в него значение командой можно, но состояние регистра при этом не изменится: следующее чтение снова даст ноль.
На первый взгляд это нарушает идею полностью одинаковых регистров. На практике небольшой специальный случай позволяет упростить множество обычных операций.
Если результат вычисления не нужен, его можно направить в r0. Нулевое значение всегда доступно без предварительной загрузки константы. Команда вроде ADDI r0, r0, 0 ничего не меняет и может использоваться как операция без действия.
Здесь специализация применяется иначе, чем в MIX. Она не распределяется между множеством регистров, каждый из которых предназначен для своей задачи. Один особый регистр добавляет универсальное свойство, которым затем могут пользоваться разные команды.
Остальные 31 регистр при этом сохраняют одинаковую архитектурную модель.
Что происходит с аккумулятором
Особенно интересно сравнить Memora8 с регистром A в MIX.
Аккумулятор долгое время был естественным центром процессорной архитектуры. Операция могла не указывать явно все свои источники и получателя, потому что подразумевалось участие A. Это позволяло экономить место в машинной команде и упрощало некоторые аппаратные решения.
В MIX значение A этой моделью не исчерпывается, но его центральная роль хорошо заметна. Кнут описывает его как регистр общего назначения полного размера, содержимое которого обычно служит операндом арифметических команд и команд сохранения. X дополняет эту модель и может работать как расширение A.
В Memora8 выделенного аккумулятора нет. Арифметическая команда явно указывает регистр результата и регистры операндов. Например, сложение получает два источника и записывает результат в выбранный регистр назначения.
Это требует нескольких бит внутри инструкции для указания номеров регистров, зато снимает жёсткую привязку вычислений к одному центральному месту.
Такой подход хорошо сочетается с фиксированным 32-битным форматом команд Memora8. Номер каждого регистра занимает пять бит, чего достаточно для выбора одного из 32 регистров. В результате одна и та же структура может использоваться большим количеством операций без необходимости вводить разные правила для аккумулятора, индексов и специальных регистров.
Индексация тоже перестаёт быть свойством особого регистра
В MIX шесть индексных регистров существуют именно для изменения адреса, содержащегося в инструкции. Поле INDEX команды выбирает нужный регистр, значение которого добавляется к адресной части и образует действительный адрес обращения.
Для времени создания MIX это очень естественная конструкция. Массивы и циклы требуют изменения адресов, поэтому специальный аппаратный механизм индексации напрямую решает распространённую задачу программ.
В Memora8 отдельного класса индексных регистров нет. Адрес при работе с памятью строится из обычного регистра и смещения, указанного в инструкции. Тот же регистр до этого может участвовать в арифметике, хранить промежуточное значение или получить адрес в результате другого вычисления.
И снова функциональность никуда не исчезает. Исчезает аппаратное разделение регистров по профессиям.
Для небольшого процессора это важно не только из-за удобства программирования. Однородная регистровая модель означает, что тракт чтения регистров, выбор операндов и запись результата может строиться вокруг одного общего механизма.
Специальные регистры или специальные соглашения
На этом сравнении хорошо виден более общий архитектурный выбор.
Можно закрепить назначение непосредственно в аппаратуре. Тогда определённый регистр всегда является индексным, другой хранит адрес возврата, третий участвует в основной арифметике. Программа получает готовую структуру, но процессор должен поддерживать различия между её элементами.
Можно поступить иначе и дать программам несколько одинаковых ресурсов. Тогда аппаратная часть знает меньше, зато компилятор и соглашение о вызовах должны договориться, как эти ресурсы использовать.
Memora8 в основном выбирает второй вариант.
Например, адрес возврата нужен при любом вызове функции. В MIX для него существует J. В Memora8 сама команда перехода может записать адрес возврата в выбранный обычный регистр, а уже соглашение о вызовах определяет, какой именно регистр обычно используется для этой цели.
Для программы результат тот же: после выполнения функции необходимо знать, куда вернуться. Однако архитектура процессора не содержит отдельного физического типа «регистр возврата».
Простота здесь означает одинаковые правила
Можно было бы сказать, что Memora8 просто использует больше регистров, чем MIX, и поэтому может позволить себе сделать их универсальными. Но дело не только в количестве.
Главное отличие заключается в регулярности.
Если операция работает с регистрами Memora8, в большинстве случаев она имеет дело с одинаковыми 32-битными объектами. Не требуется постоянно учитывать, что один регистр имеет длину полного слова, другой короче, третий не содержит знака, а четвёртый предназначен только для определённого класса операций.
Для аппаратной реализации это означает меньше разновидностей одного и того же действия. Для компилятора — более свободное распределение временных значений. Для человека, изучающего процессор, — более короткий набор правил, которые нужно держать в голове одновременно.
MIX решал другую задачу. Его специализированные регистры делают внутреннее устройство вычислений наглядным и отражают архитектурные подходы своего времени. У Кнута регистровая модель сама объясняет значительную часть того, как предполагается программировать машину.
Memora8 переносит эту границу.
Процессор предоставляет 32-битные регистры и простые операции над ними. А вопрос о том, какое значение сейчас является указателем, аргументом функции, временным результатом или адресом возврата, по возможности остаётся вопросом программы.
В этом и состоит переосмысление идеи MIX. Не отказаться от регистровых ролей вообще — без них невозможно организовать программу, — а отделить логическую роль значения от физического устройства, в котором это значение хранится.
Для Memora8 оказалось полезнее иметь почти одинаковые регистры и несколько общих правил работы с ними, чем множество аппаратно закреплённых ролей. Это ещё один пример того, как при переходе от архитектуры Кнута к реальному процессору на FPGA сохраняется сама задача, но меняется место, где она решается.