Talks

mruby machine: An Operating System for Microcontoller

There are different approaches to make an operating system.
I take an approach which takes advantage of mruby/c's VM then makes my own mruby compiler and shell program.
Though my purpose is making an useful and effective development platform for microcontroller with Ruby, I will also share some universal knowledge on how to make an OS with you.

RubyKaigi Takeout 2020

00:00:00.560 Hello everyone. Today, I am online to talk to you about the mruby machine. Let me introduce myself; I am Hasumi from Matsuya. I love sake, coffee, curry, and soba. I usually write various applications and am sometimes known as a microcontroller developer. Anyway, please check my Twitter account, as I will share some additional information there while this video is being streamed. This is our company, Monster Lab. We are a worldwide development firm, including Matsuya. Please let me know if you are interested in working with us.
00:00:56.239 Okay, let's start Chapter 1: the background of my project. According to the FAQ page of MicroPython, we generally keep the minimal configuration of MicroPython under 80k of ARM assembly code, which includes a compiler and an interactive prompt. This means a Cortex-M microcontroller with 128 KB of flash, which refers to ROM, can host a minimal version together with some hardware drivers. Regarding RAM usage, 8 KB is the minimal amount required to run simple scripts. As Python is an interpreted high-level language, the more memory you have, the more capable applications you can run.
00:02:05.360 The reference MicroPython board, Pyboard, has 128 KB of RAM. On the other hand, flashing a MOV application into 128 KB of ROM and running it on 128 KB of RAM are both evidently difficult. Mrbc is a smaller implementation of the MRuby virtual machine, but it does not have a Ruby compiler. Consequently, you have to compile Ruby scripts into VM code before embedding them. I must admit that MicroPython is really strong, but I am not giving up. Let's create something that doesn't exist yet: a small MRuby compiler.
00:03:06.720 By the way, our target microcontroller is the PSoC 5LP, which has an ARM processor, 64 KB of RAM, and 256 KB of ROM. I believe it will be sufficiently comparable if the Ruby compiler runs on the microcontroller. Now I will show you a quick demonstration. You can see the PSoC on the left window. The right window is a terminal emulator connected to the PSoC via a serial cable. I'm starting the PSoC and then typing some Ruby codes, such as 'hello world' and 'nice to meet you.' Then, I will make an instance of a LED class. The class of LED is, of course, LED. Now I can turn on the LED like this. Look at the PSoC! Yay! And I can also turn it off. Congratulations! You have just seen an MRuby compiler and a virtual machine running together on the PSoC.
00:04:59.680 Chapter 2: Now we are going to look at terms and tools. MRB is MRuby, as you know. MRBC is a command line tool of the MRuby compiler, and it is a part of MRuby. MRBC is a smaller version of MRuby. As I mentioned before, MRBC is merely a virtual machine and does not include the MRuby compiler. Therefore, we usually use MRBC to create VM code for MRVC. There are very relevant terms on this page. MMRBC is the key product of today; it means Mini MRuby Compiler. I refer to the combination of MMRBC and MRBC as MM Ruby. The MRuby machine is the title of this talk, which has its technical stack illustrated on the next page. We will be able to deal with almost everything related to microcontrollers by using Ruby. Today, I am focusing on the compiler, but other tools like shell and interrupts are also very interesting. I hope to have another chance to discuss them in the near future.
00:06:41.520 Next, I need some cross-compilation tools for ARM because the architectures of my host computer and the target controller are different. We use ARM non-EABI tools to build binaries for the ARM processor. EABI obviously means ARM architecture without an operating system; you can also refer to it as bare metal. EABI stands for Embedded Application Binary Interface. So now you know that these tools are necessary. I use three different kinds of toolchains for my project: one is the normal GCC, which is a standard C compiler. Secondly, I occasionally build binaries for Linux to ensure I don't make bugs that only appear on the ARM architecture. With this setup, you can also use GDB for debugging. The last tool is the non-EABI GCC, which is used for creating the final executable for the PSoC.
00:08:15.520 By the way, I've uploaded a Docker image for you; feel free to use it. The last topic in this chapter is the C library. There are various libraries available, such as the GNU C Library, which is the most popular. However, I do not recommend using it for microcontrollers because the code size will be too large to accommodate. In this scenario, you can instead use the newlib series. They are designed to be small and are written for reduced footprint in things like performance and memory security. Now, we are diving into MMRBC, the Mini MRuby Compiler. It's the repository of MM Ruby, including MRBC, so please check it out.
00:09:10.480 These are the features of MMRBC: it does not depend on MRuby or MRBC. MMRBC relies solely on libraries like GLIBC or newlib. MRBC can be integrated with both MRuby and MRVC. You can easily build it not only for the ARM architecture but also many other architectures, and it is small, of course. The details will be discussed later, but you can install MMRBC into 256 KB of ROM and have it run on 64 KB of RAM, just as you saw in the demonstration. MRBC uses Lemon as its parser generator instead of YACC or Bison. Lemon is originally a parser generator for SQLite.
00:10:08.000 I know that almost all of you are fond of topics related to parser generators, so I will elaborate a bit more on it. What I will explain next is what I’ve learned so far, so please correct me if I’m wrong. LALR means look-ahead left-to-right; it refers to a theory of parsing. It is sometimes thought that YACC and Bison are almost the same, but there are several differences between them. For instance, YACC is non-reentrant, while Bison is reentrant. Also, the third is safe. YACC has parser calls known as LEX style, while Bison has lexer calls known as parser style. However, you can also select all the Excel in Bison. Lemon is re-entrant and functions under lexer calls in parser style. It represents a modern formatting style of a parser generator.
00:12:16.560 According to the documents, it is faster than Bison, but I'm not sure if this claim holds true. According to what Max told me, the code size tends to be smaller with Lemon compared to Bison. Thus, I prefer using Lemon instead of Bison. Although I do not have enough time to explain it in detail, I want to mention that the grammar syntax of Flex is different from Bison. For more details about Lemon, please check the official page.
00:14:03.040 In the final chapter, we will discuss how to make it smaller than MRBC. The primary goal I have set is achieving a small footprint concerning RAM and ROM. It is now time to compare the two. First, we'll examine RAM consumption. In this chapter, I will use the MRB3 branch of MRuby to compare it with MMRBC, which I’ve written.
00:14:18.720 To simplify the comparison process, I built MRBC and MMRBC as binaries for 64-bit Linux. Both utilize GLBC's malloc and free to remain analyzable by Valgrind. Valgrind is a toolset that aids in profiling memory or detecting race conditions in multi-threaded analysis. The command to analyze memory looks like this. We also use the `ms print` command to see the results of the analysis.
00:15:20.480 Here’s a key example used to test. The code 'hello world' contains one function call, which has one argument without parentheses, and as you can see, the output is 'hello world.' This is the result of MRBC. The analysis shows a transition of memory usage in this graphical format. It indicates that MRBC used 157 KB of RAM to compile 'hello world.' On the other hand, my compiler only used 11 KB of RAM. I believe you are applauding now; thank you!
00:17:36.800 In Case 2, we will compile a slightly larger script. Here are the results of that script: MRBC used about 53 KB, while MMRBC used significantly less. This suggests that MMRBC has good potential to run on one-chip microcontrollers. However, at the same time, I think I still need to improve memory efficiency. The script from Case 2 also demonstrates the syntax MMRBC can support, including assignments, constants, method calls with parenthesized arguments, arrays, hash literals, symbol strings, and keywords, such as 'true' and 'interpolation' of strings.
00:18:48.960 My compiler can compile this syntax as it stands now, although I still have a lot to do, to be honest. Please check this roadmap if you are interested. I will conclude my talk by showing a code size comparison. These are the application codes called files that I demonstrated at the beginning of this presentation. You can use the `size` command to estimate how much ROM will be consumed, focusing on sections like the text and data sections, which comprise the machine code. These sections contain variables that have initial values. The BSS section indicates RAM size, so the total of text and data will indicate ROM consumption. It appears I still have some margin to implement more syntax for the PSoC 5LP, which has 256 KB of ROM. Here is the summary of my talk.
00:20:35.040 First, MMRBC is a Mini MRuby Compiler. The VM code generated by the compiler runs on both the ML Ruby VM and MRBC VM. While it is still incomplete in terms of syntax and memory efficiency, the MRuby machine integrates MMRBC, MRBC, shells, and hardware drivers. I hope the discussion regarding shells and peripheral drivers will serve as a topic for our next meeting. That's all for today. Thank you very much for listening! I always appreciate the RubyKaigi organizers. Thank you all.