In this post I want to talk about our efforts to use the Russian processor with the original architecture Multiklet . We are interested in transferring our Embox RTOS to this platform, as this will make it possible to use a fairly large number of applications that we have - for example, a SIP phone , which we have already talked about.
It will be about the problems that we encountered in the transfer process, and how we resolved these problems. It may be interesting not only for those who plan to use this processor, but also for those who for some reason need to switch from c99 and gcc to c89 and some compiler that is incompatible with gcc. Also in conclusion, I allow myself to add personal feelings of interaction with this platform.
About Russian reality
The kit, which we bought, is top-end, and costs quite a lot of money. Of course, it is not as expensive as Elbrus, but it is not comparable with the same raspberry. However, if you forget about it, the sent kit looked pretty decent. The price, in my opinion, should be attributed to the limitedness of the party, because it is almost a handmade job.
Photo module
Another feature we encountered was delivery time. The kit was supposed to come back in February, and came in July. However, a few kicks from our side, assurances and letters of guarantee from the multiklet - and here, finally, the long-awaited package arrived. ')
Getting Started
When we were convinced of the existence of a domestic processor, we proceeded to what we were buying this debug kit for - porting our RTOS to this platform. As I said before, the idea was that the support of the multiclet by our project would automatically allow using a wide class of applications on it with multitasking, network stack, file system, and of course blackjack.
As an experienced person and once personally confronted with original processor architectures, I immediately tried to establish contact with those who can answer our technical questions. Unfortunately, at the first stage I was not particularly successful in this issue. To questions about the compiler I was given a link to a page from which it can be downloaded, and a description of working with a processor, also present on the site.
Not a very encouraging situation, but at least the compiler was there! Although c89, he compiled the code and the examples provided. Optimism was inspired by the fact that we already met an article about porting to this FreeRTOS architecture. Therefore, we decided to move until we rest on a difficult task that we cannot get around with crutches.
Technical details of the compiler
Compiler C for Multklet is based on lcc, which, unfortunately, is not compatible with mainstream gcc / llvm / icc in everything, including the command line interface. The first attempt to compile at least one file revealed a lot of unsupported flags. The most unpleasant was the absence of the -include xh compiler option. This option includes the xh file for preprocessing, as if the first line of the compiled file was #include <xh>.
In principle, this is not a standard technique, but in this way it is very convenient to transfer, for example, generated configuration files (and we have a lot of them), or, as in our case, the compiler parameters, which will be discussed a little further.
The next difference was the provision of a compiler to the public. The fact is that lcc is only a compiler, and gcc is rather a set of utilities for compilers (ld, as, cc, ..). The very same gcc serves as a kind of wrapper for all these utilities, or more simply, it is a compiler driver. That is, it is correct to call the assembler or linker through gcc, which forwards all the parameters to the appropriate utility with the correctly set environment. In general, we had to introduce separate variables for building LD and AS, and take the AR utility from the host machine. If earlier a cross, for example mips-elf, could simply be attributed to -ld, -as and -ar, and they were generally called via CC with the corresponding flags, in this case, we had to explicitly call utilities.
Linker, of course, also presented his surprises.
The first was the absence of the -r flag (--relocatable) to create intermediate object files. We use these objects when generating our meta-information - for example, we calculate the checksums to check the integrity for each module of the system. Well, in general, this is quite a useful thing if it comes to the use of dynamic modules and libraries.
Further more. Working with static libraries leaves much to be desired. Not only can libraries be transferred only with the -l option, they also cannot contain the full path. Because of this, it is fundamentally impossible to link different libraries with the same name. In addition, the lack of support --start-group / - end-group is unpleasant.
I can also add a rather interesting and unpleasant fact, already related to the compiler: the -l option is overridden in it. In lcc, this is a synonym for --lccdir.
Summing up the subtotals, I will formulate the Wishlist to the developers of the linker compiler for the flags
Compiler option -include xh Liquor option -r, or --relocatable Full path to libraries Options - start-group / - end-group The -l option for the compiler is reserved for the linker, although this is a trifle.
Source modification
We now turn to the source itself. Let me remind you that they are c99 or even gnuc, and the compiler is c89. It is clear that there should have been problems. The first problems arose not even with the compiler, but with the preprocessor. This compiler uses the mcpp preprocessor. In general, it immediately became clear that macros with a variable number of arguments in it are processed differently than in gcc: the “tail” cannot be empty, that is, a macro with one required argument cannot be called with less than two arguments. I had to change, for example, such a macro as assert. Previously, he could have accepted not only an expression for checking, but also a string of an error message, which is sometimes very convenient. In principle, this is not the standard behavior of the macro, so we just made another assertf () macro and did not compile the source code where it was encountered.
Let's go back to the compiler. The inline keyword appeared in c90, and is not supported by the multiklet compiler. We widely use static inline functions as a macro replacement. The output was the introduction of the compiler.h file, in which the lack of inline support is determined through ifdefs, in which case the inline is declared an empty macro (#define inline / * nothing * /).
The compiler does not support the designated initializer (designated Initializers) . This problem cannot be solved with the help of the preprocessor, and we really did not want to degrade the source code to support the old standard. The c99-to-c89 tool came to the rescue , which turns c99 code into c89 on the fly.
In addition, the compiler does not support the typeof keyword, which is an extension of gnuc. We use it, for example, to describe the min and max macros:
/** @return the larger of @aa and @ab */#define max(a, b) \ ({ \ typeof(a) __max_a = (a); \ typeof(b) __max_b = (b); \ __max_a > __max_b ? __max_a : __max_b; \ }) /** @return the smaller of @aa and @ab */ #define min(a, b) \ ({ \ typeof(a) __min_a = (a); \ typeof(b) __min_b = (b); \ __min_a < __min_b ? __min_a : __min_b; \ })
In general, for integer variables, you can write simply:
#define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
which we did in several places, simply throwing out the inclusion of the header file and defining it in this way.
The biggest problem was the attributes. The compiler does not support the ability to set alignment, packing structures, placing data or code in certain sections. To do without these things is extremely difficult. For example, we have very actively used work with sections: even the system load is based on the principle of placing pointers in certain sections. Unfortunately, we could not solve this problem, so at the current stage we decided to limit ourselves only to outputting the system launch string to the serial port.
After compilation, we unpacked our bundle. As I said, he looked quite decent.
Little unpacking photo session
Well, the video of the first inclusion
But when we were going to connect the jtag, it turned out that the documentation for the board does not contain information on how to do this. There were commands for the firmware, but there was no information on how to properly plug into the jtag connector. At the same time, there were two connectors to which he perfectly approached. Experiencedly, we found out that this is the right thing to do as follows:
Photo connector
In fact, we asked questions to the multiclet, and they, it seems, have already updated the manual, adding a photo of the connector.
Run image
The last obstacle on the way to the cherished line was a bug in the linker, which they had already fixed with our submission.
The bottom line is that the ready-made examples worked, but the Embox image, in fact, did not with the same code. I immediately had suspicions about the incorrect placement of program objects in the memory. At first, we sinned on the stack, since our image was significantly fatter than in the examples, and we thought that the stack pointing to the end of the 256k memory could just overwrite something, there were such precedents. With the help of readelf it became clear that everything is fine with the dimensions, and we began to sin at the starting address. That is, we wanted to check that the program is correctly linked. It turned out that the disassembler is not included in the development kit. As a result, after the linker displays the label addresses, the assumption was confirmed. The difference between Embox and the examples was that the first object file in the examples was always crt0.o.
I asked to add support for the .section directives to the assembler and the corresponding support in the linker, to which I received an answer on the “read the documentation” forum. I read, checked and gave an example of the source code, which showed that it does not work. In general, with the help of the same krufter, the problem was solved.
And I finally saw the long-awaited line:
Unfortunately, further progress without adding a couple of features to the compiler is rather difficult, and I decided to think about what to do next: either to cut the compiler itself, or to wait indefinitely, until the compiler completes it. The latter seems not very promising, since they decided to make a c99-compatible optimizing compiler. And do not take gcc or llvm as a basis, but cut your own, referring to the fact that they do not have a registered organization of the machine.
Personal sensations
As I warned, let me express my personal feelings. In the end, the multiklet developers themselves asked about this in the article .
I will not dwell on the hardware component, I rather decently wrote barsomster in my article . I'd rather look at the problem from my bell tower from the point of view of a system programmer.
So, the processor physically exists. This, of course, pleases, but it is not clear when the Russian electronics industry will understand that the processor is not needed by itself. Intel invests a lot of money in software, and these investments exceed their investments in the development and direct production of processors.
All other manufacturers also understand that performance tablets do not make any sense if there is no possibility to develop applications and run already written software. Today, articles like “ How I tested the IDE of Multiclet ” look weird. That is, it is actually supposed to write code in assembler? No, I, of course, understand that everything that a modern programmer needs for embedded systems is an IDE with the ability to upload its program directly to the board. I am even ready to agree with the conclusion of this article:
Thus, despite the simplicity of implementation, the proposed functionality is quite enough to fully debug even large and complex projects. The updated functionality of the toolkit allows you to significantly increase the speed of development by providing an intuitive and user-friendly interface.
But I don’t understand how it will help me at least to repeat the functionality of the Arduino, not to mention the STM?
In general, my personal impressions are twofold. On the one hand, there are people who are trying to make something new, and on the other, this approach is very visible through university education. They made a processor, reported on the work done on the tests, said: “We are the best, and we do everything ourselves!”, But what about selling? Who needs it, who wants and can use this product?
I want to finish with a question for the community. Do you think there is a domestic Multiklet processor, if no real applications have been created for it yet?
PS Emotional conclusion - this is only my personal feelings. PPS The code described in the article is in the brunch of our repository. Of course, it can be downloaded and tested on a similar board.