00:00:00.240
Hello, everyone.
00:00:01.520
This is my talk about how to build your own mruby VM on the microcontroller.
00:00:08.240
Let me share my journey with you.
00:00:11.280
In 2020, I came across a mini arcade maker product that uses an ESP8266 microcontroller.
00:00:17.199
I thought I could potentially run Ruby on it because it supports MicroPython.
00:00:22.240
However, when I looked for existing solutions, there were none available for this microcontroller.
00:00:27.119
So I decided to build my own Ruby VM to allow it to run Ruby scripts on the ESP8266.
00:00:39.920
I am from Taiwan and this is my contribution to the programming community.
00:00:44.079
Using Ruby and Ruby on Rails, I help clients build their businesses through consulting and software development. We have customers worldwide, including Japan, the U.S., Taiwan, and Singapore.
00:01:19.119
Currently, I am working on a game project with friends, where the server is written in Ruby and we are adapting the client to HTML5 or Unity.
00:01:29.200
This game was open-sourced on GitHub after the company in Japan ceased operations.
00:01:31.680
We took the source code and are trying to rebuild and relaunch the game.
00:01:39.520
Now, turning to my current project, I wanted to create an attractive experience for our players by implementing a small microcontroller.
00:01:45.360
Many people think building a programming language can be very difficult, and I agree that it requires a lot of learning.
00:01:56.720
However, with Ruby, the source code is more accessible than some other languages, making it easier to understand.
00:02:05.760
This encouraged me to start this project, despite it being my first time attempting something like this.
00:02:13.279
I had read about half of Ruby's source code but still didn't fully understand how to proceed, as its complexity is significant, especially compared to other languages.
00:02:25.280
After exploring various resources, I discovered the Adobe L1BN project, which seemed relevant to my goals, specifically in running a game on the web.
00:02:38.720
I intended to allow players to use Ruby for scripting within the game, but encountered challenges and wasn't successful initially.
00:02:45.680
Despite these difficulties, I found a small Ruby VM project that can run in a web browser, comprising only around 1,000 lines of code.
00:02:51.200
This small codebase made it very easy to read and understand the implementation of a Ruby VM, allowing me to focus on developing my own.
00:03:04.800
Now, let me discuss the core functionality of the VM, based on my understanding.
00:03:13.680
The programming language VM operates in a loop that reads each opcode and defines its behavior based on the instructions.
00:03:25.040
We start our program, reading the input from the compiled binary via the Adobe compiler that converts Ruby code into opcodes.
00:03:34.640
When we encounter an opcode, we determine the next action: whether to proceed, exit the program, or continue processing.
00:03:46.400
If we find a return opcode, we finish processing; otherwise, we keep looping until all tasks are completed.
00:03:58.480
Looking at the source code of the nWb VM, you'll find a loop that continuously reads opcodes and checks each one to determine the corresponding functionality.
00:04:07.360
To build a programming language with a VM, the first question is how to read the intermediate representation (IR) from a Ruby binary.
00:04:20.320
We can achieve this by utilizing the Adobe compiler with specific flags enabled to gather detailed information about the compilation process.
00:04:29.120
The compiler will showcase the opcodes, giving us critical insights into the implementation of Ruby scripts.
00:04:38.080
For example, if we compile a simple Ruby file that outputs 'Hello, World!', we can retrieve the associated opcodes and analyze them.
00:04:49.600
Next, I will explain the structure of the Adobe binary, which contains a header and the compiled intermediate representation.
00:05:00.639
If debugging is enabled, additional information will be available, but we should be aware that some data might be stripped in production.
00:05:11.960
In most cases, the header is generally 34 bytes, containing metadata that can be skipped when processing the binary.
00:05:19.920
The IR provides detailed data regarding opcodes and local variables necessary for executing your Ruby program.
00:05:30.000
The final section of the binary will contain the executable obcodes that the VM needs to process.
00:05:39.200
As we scan through the binary's header, we then turn our attention to the IR, which serves as the foundation for executing code.
00:05:48.800
By traversing the IR, we can identify the functions, strings, and any necessary data required by our Ruby programs.
00:06:03.200
When we receive the IR, we have to arrange the data properly to ensure that our code runs as intended.
00:06:15.600
Shifting our focus, let’s talk about how to effectively execute code within our Ruby VM.
00:06:21.680
After implementing the basic features, such as loading integers and performing addition, we can also include logic that allows us to return values.
00:06:32.000
The following sections will demonstrate how to execute Ruby code and process opcodes effectively.
00:06:41.680
In this simplified code sample, each opcode (e.g., loading an integer) will be executed directly by the VM.
00:06:49.600
Once we have implemented the essential features, we can proceed to more advanced operations.
00:07:01.320
It’s important to refine our VM to handle exceptions, variables, and return values efficiently.
00:07:12.560
Now, let’s cover how to define and implement methods within Ruby and how these are called during execution.
00:07:27.760
When we define a method in Ruby, the compiler will save information about the method's location and attributes.
00:07:36.120
We can locate method definitions through a symbol table and reference them during execution when they are called.
00:07:45.040
Let’s visualize how the compilation process works, particularly for an addition method.
00:07:50.400
Once the method is defined, any subsequent calls to this method will involve a lookup in the compiled code.
00:08:00.080
We’ll illustrate this with an example in which we compile and then analyze the resulting opcodes for a simple calculation.
00:08:14.560
The compiled output will reflect the actual operations performed, allowing us to observe the internal workings of our VM.
00:08:23.920
Next, we will examine how to call C functions from Ruby, which offers further capabilities within our VM.
00:08:37.360
By sourcing a method in C, we can improve performance for frequently used functions and operations.
00:08:48.160
Understanding how to bridge Ruby and C is crucial, as it deepens the interactions available to us when executing Ruby scripts.
00:09:00.080
We will analyze how to convert method calls into C method invocations, increasing efficiency and extending functionality.
00:09:12.640
In our implementation, every time we reach a method call, we will first check if it belongs to Ruby or C and respond accordingly.
00:09:25.560
When calling C methods, we can manipulate register values directly to pass arguments and retrieve results.
00:09:37.440
This flexibility allows our Ruby VM to leverage existing C libraries, making it more powerful and extensible.
00:09:48.120
Now, let’s turn our attention to error handling and ensuring our VM remains robust during execution.
00:10:00.080
Whenever an error occurs, our VM should handle it gracefully to prevent crashes.
00:10:11.160
We can accomplish this through well-placed error checks and response mechanisms that facilitate debugging.
00:10:23.440
By following these strategies, we can build a resilient Ruby VM tailored for microcontroller deployments.
00:10:34.960
Next, we’ll explore a simple demo showcasing my progress running a Ruby VM on a microcontroller.
00:10:48.640
I purchased a mini arcade station that utilizes a microcontroller unsupported by existing projects.
00:10:58.720
This motivated me to develop my own version of a Ruby VM tailored to the limitations of the hardware.
00:11:06.880
I also integrated APIs with Arduino, allowing me to render graphics generated by Ruby code on the microcontroller.
00:11:20.840
In the demonstration, I will showcase a simple animation built out of Ruby-based commands.
00:11:34.240
Please take a look as I run this Ruby code and watch it render directly on the mini arcade station.
00:11:48.080
Here, you can see the text being drawn on the screen as a result of the Ruby code executed by my VM.
00:12:02.000
This work involved careful interactions between the microcontroller and my Ruby VM implementation.
00:12:10.040
Additionally, I am currently writing a series of articles in Chinese detailing this project, featuring prototype code as well.
00:12:25.920
If you're interested, feel free to scan the QR code to access the articles and GitHub repo.
00:12:37.440
Looking ahead, I plan to enhance this Ruby VM with more features, continuing my exploration into embedded programming.
00:12:50.720
I've had a lot of fun working on this, but I also have other projects to balance, including IoT devices.
00:13:00.800
Overall, building your own Ruby VM and generating outputs from it can be an enjoyable endeavor.
00:13:13.440
Thank you all for listening! This concludes my talk about creating your own Ruby VM.
00:13:24.960
I hope you found this session insightful and feel empowered to explore similar paths.
00:13:34.880
I encourage you all to start your own projects and learn how to run Ruby in various environments. Thank you!