Do-it-yourself microcontroller

Trying to master the controllers and already owning FPGA programming skills, I got a bad idea. Came, knocked and went in. It is dedicated to all those to whom bad thoughts come and who are interested in how others deal with this phenomenon.

There was an idea to draw your controller, not limited by the number of peripherals, RAM and other parameters, except for the FPGA capacity. Let's say the controller contains 5 UARTs, and desperately need a sixth, you have to dodge. And why, if you can just click the mouse and add the necessary? Or vice versa, the problem is well solved on five controllers with a capacity of 5, 32, 20, 32 and 20 with an unpredictable number of communication lines between them. It’s a pity to use five 32 arresters, the resource is always a pity, and combining two subtasks on one core is ugly or something.

The response time to the interrupt in the controllers is quite long. Yes, the interrupt controller monitors inputs (for some reason limited in number) regardless of the kernel. But before you start executing the interrupt code, say, read the port, you need to save the general registers and then restore them. And this is not one clock cycle, from the point of view of program logic, rewriting registers onto the stack and returning the same values ​​back. Of course, it fits into the concept of real time, but you can do it instantly: the code with low priority was executed, at the next clock cycle, due to the urgent need, a high-priority timer interrupt starts, and after the clock code is processed to process the external data stream, because there everything is needed quickly.

Of course, all these problems are contrived and solved both easily and simply. But a bad thought does not seek such solutions, it just wanders in a crowded space of consciousness and pushes to make non-standard. And, if the young engineer is on vacation, then forgive the wife and children, but dad does not "sit at the computer again", but grows professionally. Moreover, sometimes you want to do not someone invented tasks, but your own, completely your own.


Fig. 1. Timers. Add as much as you want. Note the grammatical error. I am ashamed, but I do not want to install Builder for recompilation.

Allow me to introduce you to a controller whose architecture, not so different from all the others, is rather not adopted. The list of literature read before the beginning of work has long been forgotten, the thoughts of many people from different computer eras have been used, forgive me my forgotten teachers. But you do not have to deny me. Yes, and it did not carry money, so there is nothing to share.

I must say right away that the controller took place, is stitched in Spartans of all generations and successfully works in the vastness of the CIS and one country in the Baltic. Now, much would have been done differently, but any changes to me are already lazy, and what happened is what happened. And this is what happened.

- The capacity of the controller is from 1 to 32, with or without a sign. (I don’t remember if I checked the work at low bit depths). An additional code is used.
- The number of input / output ports is not limited by anything, the capacity is limited by the capacity of the core.
- The number of timers is also not limited. For each timer, you can set your own interrupt handler.
- An interrupt handler with an infinite number of inputs, each input has a priority of 0 to 99 (a limitation due to the "already large number"). Ability to disable all interrupts or low priority only.
- The number of serial ports of the UART type is unlimited, the bit capacity is limited by the core capacity.
- The frequency divider is made poorly and incorrectly, but regularly produces any frequency for any periphery or just outside the controller.
- The coprocessor. About him below.

That is, we have a controller that supports the basic operations of arithmetic and other bit changes in words (plus, minus, shift, bitwise logic ...). It also accesses internal memory and stores program code in the same way. The memory is used block, it is platform-dependent and in the program settings you must definitely specify which chip will be the controller's carrier. All operations in any direction of actions are performed in one step, this may not always be good, but it simplified the design of the architecture. An exception is an integer divider, the functions of which are implemented in the coprocessor; division is performed slowly but surely. The division algorithm was chosen the simplest - bitwise.

I would like to talk about the command code, but I don’t remember what it consists of. Based on the principle of "do not use what is not used," even the length of the command code is not a constant value, especially its contents. Say, if there are 14 instructions in the compiled program, then each instruction is encoded with 4 bits, if 18 instructions are used, the fifth bit is highlighted. Plus, each bit is added with a bit of length, if it is 0, then the command is single, if 1 is double, or vice versa, it does not matter. A double command is needed for operations containing the address of RAM or ROM. Add to this that the address buses also have non-constant lengths, and we get a complete mess in the command code, it makes no sense to consider it with any disassembler, just like the assembler in this controller.

Fort is the language that allowed me to realize these strange ideas. The fort is simple and low level. Writing a compiler of this language is a pleasure. Well, of course, all language constructs are not supported, only the basic ones for sending data and changing them.

Fig. 2. The management is rather modest. Indiscreet was never written.

Fig. 3. The second part of the manual. I don’t know why, but the window cannot be expanded. There is also a third part, but it’s completely boring.

And, of course, we have a stack controller. That is, Fort operates in its natural environment - in the stack, in the hardware stack, and not in a slow software one. "All for the beat!" - The second motto of the project. The hardware stack allowed us to immediately start executing data processing instructions when switching to a function or calling an interrupt, without having to save the contents of the interrupted process. The "new" data is simply pushed onto the stack from above, the "old" data goes deep and is perfectly stored there. Then, the “new” data, participating in various operations, safely transfers to RAM or other places, and the “old” data is pushed to the top. When you return to the interrupted section of code, no one will notice anything. The address of the interrupted code is stored in another stack, and the maximum number of interrupted processes depends only on the depth of the Return Stack. This value is adjusted during compilation, even if it is a "very large number". Parameters in the function are also passed through the stack.

Stackcpu - this is what the controller is called, for some reason in Latin, although you can write code in Cyrillic. What I am doing, I will give an example of the function "change_bits_in_word":


Where: “read_from_necessary_port”, “change_read_from_necessary_port”, “write_to_required_memory_cell” - functions that perform certain actions.

Well, am I nuts crazy ? I will give more evidence, a traffic light control program:

	зелёный потушить, жёлтый потушить, красный зажечь.
	пятьдесят секунд ждём…
	зелёный потушить, жёлтый зажечь, красный потушить.
	четыре секунды ждём…
	зелёный зажечь, жёлтый потушить, красный потушить.
	сорок секунд ждём…
	зелёный уменьшить_яркость_до_нуля, жёлтый гори, а красный не_гори.
	четыре секунды ждём…
0 UNTIL		\бесконечный цикл

Well, crazy crazy ? The third principle of the project: “Literary language in the management of electronics!” Although, as practice has shown, writing so programs is quite tedious. For Fort experts, I’ll inform you that my compiler treats the period as a separator, and the comma too. Of course, it is better to use the C language, but the C compiler is too tough for me, and the architecture does not allow using third-party compilers.

Fig. 4. Development environment with a compiler and linker report.

How much FPGA capacity does the controller take? But who knows? It all depends on the bit depth of the number, the selected periphery, something else, and the text of the program. The controller will not have a multiplier if it is not found in the program code, or there will be no divider if it is not used by the programmer. By a programmer I mean myself, since there are no other programmers for this controller (the principle is "not to be used by those who do not use"). By block memory for data RAM and instruction ROM: a minimum of two blocks, a maximum of the entire block memory of the chip.

The maximum frequency of work is calculated only empirically, for a specific architecture. One of my 24 bit controllers did not work at 48 Mhz in Spartan2, it worked at 40Mhz. In Spartan6, 32 bit was running on a hundred Mhz. Or maybe a couple of hundred will work, nothing in it is so complicated.

Fig. 5. Here is the code the processor will see. Please note that one FORTH command is one processor core command - one system clock cycle.

First PS: I’ll mention one possibility of a coprocessor - a filter. Normal IIR filter. But what’s unusual about him is that he uses a floating point. Not that it would make any sense, I just read some book about the form of representing numbers, and decided: this is your floating point nonsense , let's do it.

Fig. 6. Modeling the results of the filter. The logic of the VHDL code is calculated with an accuracy of bitik.

There were also plans to turn the project into a system on a chip: adding various blocks written in VHDL to the peripherals of the controller. And it seems not so difficult, but the fuse has dried up. Bad thoughts have left me, and wander somewhere between programmers and electronic engineers. And their name is Startups now.
So, if someone comes to you and introduces himself as a Startup, think about whether or not there is some kind of Time Killer.
And one more PS: On the other hand, during the work on the Stackcpu project, I learned three good programming languages quite well :
1. FORTH, or rather, a certain subset of it needed to verify the controller’s performance.
2. C ++, in pure C it would be hard to write a development environment and compiler.
3. VHDL, the letters of this language are the controller.

It is clear that you can talk for a long time, but that's enough. I’ll go to do other people's ideas, but with my implementation!
Actually the controller (half a megabyte):

Also popular now: