The post has been translated automatically. Original language: Russian
The processor does not have enough RAM alone. It needs to interact with timers, event queues, memory controllers, page movers, loading facilities, cryptographic blocks, and other system components.
One of the usual ways to solve this problem is to make device registers part of the shared memory address space. The processor accesses them in much the same way as it does regular data. Memora8 explores a different approach.: regular memory and device management are architecturally separated, and native SB and SBI commands are allocated for the system bus.
This small ISA change defines a much more important boundary within the entire system.
Memory and device are not the same thing.
When the processor reads regular memory, the meaning of the operation is quite simple: there is an address where the data is located. When writing, the new value should be at the specified address.
Accessing the device has a different nature. A record can not just save a number, but trigger an action: move a page, queue a value, change the state of the controller, or start calculating. Reading can also return not the contents of a memory cell, but the current state of the device or the result of a executed command.
Therefore, in Memora8, the system bus is considered not as another piece of memory, but as a separate mechanism for processor interaction with hardware components.
This separation makes the intention of the operation explicit already at the machine command level.
Two commands instead of a lot of special instructions
It would be possible to add separate commands to the ISA for each hardware device. For example, one for a timer, another for a queue, a third for moving pages, and several more for future components.
But then the processor's instruction set would have to be changed along with the development of peripherals.
Instead, Memora8 considers two universal commands.:
SB rd, rx, rc
SBI rd, rx, imm17Both perform the same action — read or write the system bus word. The only difference is where the control value comes from.: SB gets it from the register, and SBI gets it directly from the instruction itself.
Therefore, the ISA is not required to know what exactly is behind the system bus. It defines only a universal access mechanism.
One control format for reading and writing
A 17-bit control value is used for SB and SBI. One bit determines the direction of the operation, the remaining 16 bits set the address inside the system bus.:
control[16] direction
control[15:0] addressIf the highest bit is zero, the processor writes the value to the system bus. If it is equal to one, the processor reads the value:
control[16] = 0
SystemBus[address] = rx
control[16] = 1
rd = SystemBus[address]Thus, the same pair of commands covers both exchange directions.
It is convenient to use SBI for a permanent address. If the address is calculated while the program is running, SB is applied.
Why do I need 16 bits of address at once?
The current system bus buffer is small. A few dozen words are enough for it, so the 16-bit address field looks redundant today.
But the cost of the field itself is already paid for in the instruction format. If you leave only five bits, and after a few generations you will need more space, you will have to change the ISA or introduce additional addressing methods.
Therefore, Memora8 immediately leaves 16 bits for the system bus address. The current implementation uses only a small part of the range, and the rest of the space remains a reserve for development.
This is one of the cases when a small margin in coding practically does not complicate anything in hardware, but it allows you not to change the instruction set in the future.
Why doesn't the system bus go through the regular memory?
There is a custom path for regular Memora8 memory: page windows, physical page selection, bank memory, and ownership rules.
The system bus does not need all this.
A request to a timer or queue should not go through the page display mechanism just because the processor needs to pass a 32-bit number to the device. Therefore, SB and SBI form a separate path from the processor to the system devices.
This separation also makes it easier to check access rules. A normal memory operation cannot accidentally turn into a command to the device, and accessing the system bus is visible directly from the executed instruction.
These commands must be privileged
Direct control of system devices should not be available to any program.
Operations that affect memory, processor performance, and the state of the entire computing node can be performed via the system bus. Therefore, SB and SBI are treated as privileged commands.
If an ordinary user program tries to execute such an instruction, the processor must generate a system violation — MTR. The operating system already determines how to handle this event.
This is another advantage of a separate path: the boundary between conventional computing and system management exists not only in the program's conventions, but also directly in the ISA.
What happens to the SB name?
In the original instruction set, SB meant writing one byte to memory — the familiar Store Byte.
But when Memora8 switches to exclusively 32-bit memory operations, such a command becomes unnecessary. Regular memory leaves LW and SW, and the released code can be reused.
In the new ISA card, the SB designation gets a different meaning — referring to the system bus. Together with SBI, it forms the usual pair for Memora8: a variant with a control value in the register and a variant with a direct value in the instruction.
This is not an attempt to preserve the old name at any cost. It's just that after deleting a byte entry, the corresponding ISA code is released for an operation that the system architecture needs much more.
At the language level, I don't want to write SB and SBI.
Machine instructions are convenient for the processor and compiler, but the system program does not have to constantly manually collect system bus addresses and choose between SB and SBI.
Therefore, the unary form of the % operator is considered for Sekura JS.
At the same time, the usual binary % retains the usual mathematical meaning — the remainder of the division.:
r = a % b;And the unary % gets a completely different purpose: to work with the system bus. In Sekura JS, the same graphical operation can have different semantics in binary and unary form.
Easy reading through %
For example, reading the system bus word can be written as:
status = %7;The meaning of the expression is very simple:
status = SystemBus[7]If the index is known at compile time, the compiler can use SBI. If it is calculated by the program:
status = %index;the compiler can use the SB register form.
Thus, the choice of a specific machine instruction disappears from the source program.
The command to the device also becomes an expression of the language.
A window of 32 words is considered for system devices. In the new model, the first 31 words are used for arguments, data, and result, and the last word is the control word.:
word[0..30] arguments / data / result
word[31] commandThe control word is written last and runs the command. Therefore, a call without arguments may look like this:
%control;A command with multiple arguments:
%{arg0, arg1, arg2, control};The compiler turns such a construction into something like the following sequence:
write arg0 to word[0]
write arg1 to word[1]
write arg2 to word[2]
write control to word[31]It is the last record that triggers the operation.
This results in a rather important separation of levels. The programmer sees the system device call, the compiler decomposes it into calls to the system bus, and the processor executes them through SB and SBI.
You can only read the desired results.
The same unary % is considered for receiving the device's response.
One word:
status = %7;A few selected words:
{a, b, c} = %{0, 3, 7};In this case, it is the words 0, 3 and 7 that are read, and not the entire buffer in a row.
To get all the words of the answer, the short form is considered.:
data = %{..};It corresponds to reading the range 0..30. The control word 31 is not included here, as it has a separate purpose.
This way, the system bus gets a fairly compact representation in the language without introducing a large set of built-in functions.
Why does unary % need a separate meaning?
At first glance, using % for the system bus looks unusual. But in the system language, it is not only the familiarity of the symbol that is important, but also the density and unambiguity of the construction.
Form:
%7it does not look like a normal memory access and immediately shows that the program does not interact with a variable or a pointer, but with a special system space.
This is a matter of principle. The unary % does not create a pointer, and the usual rules of arrays and address arithmetic do not apply to it. It denotes another language operation, which is then directly translated into a special processor path.
In addition, such an operator can only be allowed to Sekura JS system modules. Then the privilege boundary will exist simultaneously in the language, compiler and processor.
There's a shortcut from the language to the device.
As a result, the model in question looks like this:
Sekura JS
%
↓
SB / SBI
↓
System Bus
, system device
In this chain, there is no need to pretend that the device is a regular memory. At each level, the same meaning of the operation is preserved: the program accesses the system component.
For Memora8, this is more important than saving one or two instructions. The fewer hidden transformations there are between the expression of the program and the action of the hardware, the easier it is to understand the behavior of the system and formally describe its properties.
That is why the system bus receives its own ISA commands, and Sekura JS receives its own language form for working with them.
SB/SBI and the new unary% semantics are still being tested as part of the architecture revision. But the basic idea has already been defined.: regular memory is responsible for data, while the system bus is responsible for managing hardware devices, and this difference should be visible from the source code to the processor itself.
Процессору недостаточно одной оперативной памяти. Ему необходимо взаимодействовать с таймерами, очередями событий, контроллерами памяти, устройствами перемещения страниц, средствами загрузки, криптографическими блоками и другими компонентами системы.
Один из привычных способов решить эту задачу — сделать регистры устройств частью общего адресного пространства памяти. Процессор обращается к ним почти так же, как к обычным данным. В Memora8 исследуется другой подход: обычная память и управление устройствами разделяются архитектурно, а для системной шины выделяются собственные команды SB и SBI.
Это небольшое изменение ISA определяет гораздо более важную границу внутри всей системы.
Память и устройство — не одно и то же
Когда процессор читает обычную память, смысл операции достаточно прост: есть адрес, по которому находятся данные. При записи новое значение должно оказаться по указанному адресу.
Обращение к устройству имеет другую природу. Запись может не просто сохранять число, а запускать действие: переместить страницу, поставить значение в очередь, изменить состояние контроллера или начать вычисление. Чтение тоже может возвращать не содержимое ячейки памяти, а текущее состояние устройства или результат выполненной команды.
Поэтому в Memora8 системная шина рассматривается не как ещё один участок памяти, а как отдельный механизм взаимодействия процессора с аппаратными компонентами.
Такое разделение делает намерение операции явным уже на уровне машинной команды.
Две команды вместо множества специальных инструкций
Можно было бы добавлять в ISA отдельные команды для каждого аппаратного устройства. Например, одну для таймера, другую для очереди, третью для перемещения страниц и ещё несколько для будущих компонентов.
Но тогда набор команд процессора пришлось бы менять вместе с развитием периферии.
Вместо этого в Memora8 рассматриваются две универсальные команды:
SB rd, rx, rc
SBI rd, rx, imm17Обе выполняют одно и то же действие — читают или записывают слово системной шины. Разница только в том, откуда берётся управляющее значение: SB получает его из регистра, а SBI непосредственно из самой инструкции.
Поэтому ISA не обязана знать, что именно находится за системной шиной. Она определяет только универсальный механизм доступа.
Один управляющий формат для чтения и записи
Для SB и SBI используется 17-битное управляющее значение. Один бит определяет направление операции, остальные 16 бит задают адрес внутри системной шины:
control[16] направление
control[15:0] адресЕсли старший бит равен нулю, процессор записывает значение в системную шину. Если он равен единице, процессор читает значение:
control[16] = 0
SystemBus[address] = rx
control[16] = 1
rd = SystemBus[address]Таким образом, одна и та же пара команд покрывает оба направления обмена.
Для постоянного адреса удобно использовать SBI. Если адрес вычисляется во время работы программы, применяется SB.
Зачем сразу 16 бит адреса
Текущий буфер системной шины невелик. Для него достаточно нескольких десятков слов, поэтому 16-битное поле адреса сегодня выглядит избыточным.
Но стоимость самого поля уже оплачивается форматом инструкции. Если оставить только пять бит, а через несколько поколений потребуется большее пространство, придётся менять ISA либо вводить дополнительные способы адресации.
Поэтому Memora8 сразу оставляет 16 бит под адрес системной шины. Текущая реализация использует лишь небольшую часть диапазона, а остальное пространство остаётся резервом развития.
Это один из случаев, когда небольшой запас в кодировании практически ничего не усложняет аппаратно, но позволяет не менять набор команд в будущем.
Почему системная шина не проходит через обычную память
Для обычной памяти Memora8 существует собственный путь: окна страниц, выбор физической страницы, банковая память и правила владения ею.
Системной шине всё это не требуется.
Запрос к таймеру или очереди не должен проходить через механизм отображения страниц только потому, что процессору необходимо передать устройству 32-битное число. Поэтому SB и SBI образуют отдельный путь от процессора к системным устройствам.
Такое разделение также облегчает проверку правил доступа. Обычная операция памяти не может случайно превратиться в команду устройству, а обращение к системной шине видно непосредственно по исполняемой инструкции.
Эти команды должны быть привилегированными
Прямое управление системными устройствами не должно быть доступно любой программе.
Через системную шину могут выполняться операции, влияющие на память, работу процессоров и состояние всего вычислительного узла. Поэтому SB и SBI рассматриваются как привилегированные команды.
Если обычная пользовательская программа попытается выполнить такую инструкцию, процессор должен сформировать системное нарушение — MTR. Уже операционная система определяет, как обработать это событие.
Это ещё одно преимущество отдельного пути: граница между обычным вычислением и управлением системой существует не только в соглашениях программы, но и непосредственно в ISA.
Что происходит с названием SB
В первоначальном наборе команд SB означала запись одного байта в память — привычное Store Byte.
Но при переходе Memora8 к исключительно 32-битным операциям памяти такая команда становится не нужна. Обычная память оставляет LW и SW, а освободившийся код можно использовать повторно.
В новой карте ISA обозначение SB получает другой смысл — обращение к системной шине. Вместе с SBI оно образует обычную для Memora8 пару: вариант с управляющим значением в регистре и вариант с непосредственным значением в инструкции.
Это не попытка сохранить старое название любой ценой. Просто после удаления байтовой записи соответствующий код ISA освобождается для операции, которая нужна системной архитектуре значительно больше.
На уровне языка не хочется писать SB и SBI
Машинные инструкции удобны процессору и компилятору, но системная программа не должна постоянно вручную собирать адреса системной шины и выбирать между SB и SBI.
Поэтому для Sekura JS рассматривается унарная форма оператора %.
Обычный бинарный % при этом сохраняет привычный математический смысл — остаток от деления:
r = a % b;А унарный % получает совершенно другое назначение: работу с системной шиной. В Sekura JS одна и та же графическая операция может иметь различную семантику в бинарной и унарной форме.
Простое чтение через %
Например, чтение слова системной шины можно записать так:
status = %7;Смысл выражения очень простой:
status = SystemBus[7]Если индекс известен во время компиляции, компилятор может использовать SBI. Если он вычисляется программой:
status = %index;компилятор может использовать регистровую форму SB.
Таким образом, выбор конкретной машинной инструкции исчезает из исходной программы.
Команда устройству тоже становится выражением языка
Для системных устройств рассматривается окно из 32 слов. В новой модели первые 31 слово используются для аргументов, данных и результата, а последнее слово является управляющим:
word[0..30] аргументы / данные / результат
word[31] командаЗапись управляющего слова выполняется последней и запускает команду. Поэтому вызов без аргументов может выглядеть так:
%control;А команда с несколькими аргументами:
%{arg0, arg1, arg2, control};Компилятор превращает такую конструкцию примерно в следующую последовательность:
записать arg0 в word[0]
записать arg1 в word[1]
записать arg2 в word[2]
записать control в word[31]Именно последняя запись запускает операцию.
Получается довольно важное разделение уровней. Программист видит вызов системного устройства, компилятор раскладывает его на обращения к системной шине, а процессор выполняет их через SB и SBI.
Можно читать только нужные результаты
Тот же унарный % рассматривается и для получения ответа устройства.
Одно слово:
status = %7;Несколько выбранных слов:
{a, b, c} = %{0, 3, 7};В этом случае читаются именно слова 0, 3 и 7, а не весь буфер подряд.
Для получения всех слов ответа рассматривается короткая форма:
data = %{..};Она соответствует чтению диапазона 0..30. Управляющее слово 31 сюда не входит, поскольку имеет отдельное назначение.
Так системная шина получает достаточно компактное представление в языке без введения большого набора встроенных функций.
Зачем унарному % отдельный смысл
На первый взгляд использование % для системной шины выглядит необычно. Но в системном языке важна не только привычность символа, а плотность и однозначность конструкции.
Форма:
%7не похожа на обычное обращение к памяти и сразу показывает, что программа взаимодействует не с переменной и не с указателем, а с особым системным пространством.
Это принципиально. Унарный % не создаёт указатель, к нему не применяются обычные правила массивов и арифметики адресов. Он обозначает другую операцию языка, которая затем непосредственно переводится в специальный путь процессора.
Кроме того, такой оператор можно разрешить только системным модулям Sekura JS. Тогда граница привилегий будет существовать одновременно в языке, компиляторе и процессоре.
От языка до устройства получается короткий путь
В результате рассматриваемая модель выглядит так:
Sekura JS
%
↓
SB / SBI
↓
System Bus
↓
системное устройствоВ этой цепочке нет необходимости притворяться, что устройство является обычной памятью. На каждом уровне сохраняется один и тот же смысл операции: программа обращается к системному компоненту.
Для Memora8 это важнее экономии одной или двух инструкций. Чем меньше скрытых преобразований находится между выражением программы и действием аппаратуры, тем проще понимать поведение системы и формально описывать его свойства.
Именно поэтому системная шина получает собственные команды ISA, а Sekura JS — собственную языковую форму для работы с ними.
Сейчас SB/SBI и новая семантика унарного % ещё проходят проверку как часть пересмотра архитектуры. Но основная идея уже определена: обычная память отвечает за данные, системная шина — за управление аппаратными устройствами, и это различие должно быть видно от исходного кода до самого процессора.