A little less than a year ago the article
"Microprocessor" out of the garage " was published
" and, perhaps, now is a good time to remind you of the project again.
Perhaps the main news is the expansion of the command system, called "Version 1.1". Its difference from the previous one is extended addressing capabilities. But first things first. To imagine what is at stake, take a look at the command system map (the image is clickable):

First of all, it was her desire to bring to your court. When designing the command system, two basic requirements were defined - good extensibility and high code density. Reserved opcodes are marked in yellow in the picture. As you can see from the picture, we managed to fulfill the requirements of extensibility. However, yellow “cells” are not the only opportunity for expansion - some reserve is built into the unused bits of multibyte opcodes. In addition, two prefixes (NOTCH and KOL) can extend the semantics of opcodes. As can be seen from the image, the number of single-byte prefixes can be increased without serious consequences. These factors allow us to declare outstanding expansion opportunities. But that is not all. Currently, the maximum instruction length is limited to five bytes - this size was chosen based on the capabilities of our inexpensive FPGA. Imagine how you can extend the command system if you assign operation codes in the range from 0xf0 to 0xff for longer instructions - six bytes, seven ... the length of the instruction can be limited only by common sense. So, I hope that no one has any doubts about the possibilities of expanding the system of commands, if you still have them, you are welcome to discuss them in the comments.
')
And what about the code density? Yes, Habr is harsh and does not like fictional data. According to subjective estimates, the current code density can compete in code density with the first versions of processors with the RISC architecture. For example, if we consider the very first versions of ARM and MIPS, then it seems that version 1.1 surpasses them in this parameter. As for x86 and modern RISC, thanks to the wealth of commands from these architectures, the code density is higher. However, if you properly exploit the potential expansion options, then by using the “Code Density” parameter you can surpass modern popular architectures.
I am sure that many programmers who have experience writing in x86 assembler, a quick glance at the table with instructions is enough to say "I can write on this assembler." I don’t know how the names of assembler monitors are protected by patents, but they are, if possible, chosen to coincide with x86. Separately, I would like to say about the instructions from the range 0xd0-0xd7. These are four-byte instructions, the second byte of which defines general-purpose registers, and the third and fourth serve for extended addressing.

Bit S / D determines which of the arguments (four-bit codes of registers in the second byte) is a pointer - the first or second register. Three bits are reserved for further extensions and must be set to 0, the remaining bits define an unsigned number added to the pointer for indirect addressing. These operations appeared to simplify work with structured data. You can
read about it, for example, right here -
everest.l4os.ru/aliases_for_registersCharacteristically, the code was originally developed as fully positionally independent and in the command system you will not find a single jump instruction at the absolute address, neither conditional nor unconditional. All transition addresses are represented as offset relative to the team counter. What for? This is done to implement at the architecture level 100% position-independent machine code. Need a constant? Choose it by offset relative to the program counter. You need a static variable, address relative to the program counter. However, implementation details of different addressing modes are reliably hidden behind assembler macros. The answer to the question of how to call system functions without absolute addressing is hereinafter referred to.
Actually, all of the above refers to the command system. You probably appreciated it, perhaps even agreed with something, but ... it was 20 years late. The main areas of application for microprocessors are already divided between x86, arm, mips and simple microcontrollers. Extensibility and code density are the latest things that the device developer will look at when choosing a microprocessor. What gives hope that the project will be interesting to developers? If we are talking about a system of commands, then look at the single-byte instructions
IDLE ,
TASK_ID ,
SEND ,
RECV ,
LOCK ,
FREE .
The chip of the processor is that within it is hidden a small part of the operating system that manages tasks and the very concept of the task is “wired” in the microprocessor. New instructions just serve to support multitasking. The IDLE instruction performs unconditional logging to the scheduler. Actually unnecessary instruction, useful only for debugging the scheduler itself. The TASK_ID instruction will return the identifier of the active task and the number of ticks until the next scheduled time distribution operation. The pair LOCK and FREE instructions serve to capture and free the message buffer. In this case, despite the coincidence of the name of the LOCK instruction with the x86 instruction, it performs completely different functions. Since the processor operates on the concept of a task, we need the means to interact with the tasks. Using the LOCK instruction, the task captures the message buffer, and using the FREE instruction, releases the message buffer. The message buffer is 64 registers, the exchange with which occurs using the instructions SET_MR (writing the message register value from the RON) and GET_MR and (reading the message register in the RON).
Of course, the most important instructions for the sake of which the entire project was started, are the SEND and RECV instructions - instructions for sending and receiving messages. These instructions have two arguments - the number of the task for interaction and the timeout of the operation (specified in registers). The simplest way to give a task time to the system or implement a delay is to send a message to yourself or wait for a message from yourself - the scheduler simply will not transfer control to the blocked task before the message timeout expires.
SEND and RECV synchronous operations - in order for the message to pass between tasks, one of the tasks must be completed by RECV, and the other by SEND. In most cases, this means that the first task that completed one of these instructions will be blocked while waiting for another task to be completed. If for some reason the blocking is undesirable, then a zero timeout is set and, if one of the parties is not ready, instead of blocking, the task receives a status indicating timeout.
At the time of sending the message, the message buffer that was previously captured by the LOCK instruction is switched to the task of the message receiving. The task that received the message, after working with the buffer, should release it. For example, a call to the
puts library function would look like this:
LOCK; Message Buffer Capture
SET_MR MR0, R2; setting message id
SET_MR MR1, R3; setting the message argument
SEND; message transfer
RECV; waiting for a reply to a message
GET_MR R0, MR0; read return code
FREE; release message buffer
This code is simplified as much as possible for ease of understanding. In this example, the FREE instruction releases the message buffer received by the RECV instruction, since the buffer captured by the LOCK instruction is delegated to the target task when the message is transmitted.
Despite the seeming complexity and unusualness of the solution, from the point of view of the application programmer nothing changes - the library functions carefully hide implementation details. But system programmers and library developers will have to try - they will have to start by saying that any program interaction should be described as a protocol describing the format of requests and responses - a complex program complex is described as a set of interacting subjects that solve certain tasks through the interaction.
All experiments are carried out with this miracle - the Mars Rover 2:

Thanks for attention. First of all, I would like to discuss the command system, since it is already working in hardware. As for the hardware extensions for multitasking, they are not yet ready - information about the support of multitasking is provided for informational purposes, and the actual implementation may not correspond to the material in the article.