Native 64-bit Arm host support, which is now available for both Linux and macOS via dotnet portable packages, brings a significant efficiency improvement for developers running the Renode simulation framework on Mac workstations, but also paves the way for more complex use cases, such as running Renode on Arm-based server infrastructure.
Up until now, we have been using the Rosetta binary translation tool developed by Apple to run Renode on 64-bit Arm Mac machines. In this article we describe our recent efforts to transition from the Rosetta compatibility layer to native 64-bit Arm host support in Renode. The Rosetta-based approach involved translating instructions from guest
(e.g. RISC‑V, Arm, POWER etc.) to x86_64
and then to aarch64
. With native support, we remove the extra translation step, which provides a considerable performance boost (even 2-3x speedup compared to the previous approach).
Binary translation in Renode
The process of binary translation in Renode is similar to that of a regular compiler but instead of compiling a programming language like C into machine code, it compiles one type of machine code into another. For example, when Renode runs a RISC‑V guest program, the RISC‑V machine code acts as the source code, and Renode, through its translation libraries, turns it into native (x86 or Aarch64) instructions.
This process can be divided into five steps:
- Step one: Disassemble the guest instruction
- Step two: Translate the guest instructions into internal intermediate representation
- Step three: Run optimization passes on the internal representation
- Step four: Assign host registers to required values
- Step five: Translate the intermediate representation into native instruction
Step one and two is usually called the front end, step three is the middle end and step four and five make up the back end.
Native 64-bit Arm host support in Renode
In order to enable native Aarch64 support, we had to adjust the last two steps in the binary translation process: register assignment and native instruction generation. Since Aarch64 is very different from x86, the latter part was more or less written from scratch.
Since we are generating native instructions directly with no assembler, the individual instructions are constructed by using bitwise operations on the machine code, usually represented in hex, which involves setting individual ones and zeroes to form the instruction. So to make a simple branch and link instruction, the back end has to compute the offset to the label and then emit an opcode 0x94000000 | (offset & 0x3FFFFFF)
, while in an assembler you would just write bl label
. For the initial implementation we focused on keeping it as simple as possible to facilitate debugging, however we've already identified several potential code optimizations, which means Renode's performance can be improved even more.
Enabling support for macOS required the addition of split buffer views. Normally the code is generated and executed in the same buffer, but this is not permitted on Aarch64 macOS, as a memory region can only be either writable or executable, never both. This is a security feature which makes certain types of software exploits harder. Therefore, several parts of Renode’s translation libraries had to be updated to support two different "views" of the same underlying memory with two mapped regions, one with read-write
permissions and one with read-execute
permissions, but both corresponding to the same memory on the host.
Building and testing
The 64-bit Arm version of Renode can be installed in two ways, using a pre-built package or by building from source. For macOS the latest package can be found here, and for Arm Linux here. To build from source for 64-bit Arm, compile Renode with the following command ./build.sh --net --host-arch aarch64
. Full instructions for building can be found in the documentation.
To test the implementation, we compared the runtimes of a few different samples on the new native back end and on x86 under Rosetta. The data was gathered on an M4 Mac mini with 16GB of RAM. The tested samples include Versatile
, a single core 32-bit Arm platform (as an example of a typical embedded use case), HiFive Unleashed
which is a multicore 64-bit RISC‑V platform, and Cortex-A53
, a multicore 64-bit Arm platform. The table below provides a summary of the results, with time shown as mean time ± standard deviation in seconds.
Improved Renode performance on Mac workstations
The performance boost achieved by running Renode with native 64-bit Arm host support benefits primarily Mac users, but also the growing number of developers working on other Arm-based computers such as Chromebooks, Raspberry Pi 5 or NXP i.MX8-based dev boards, and server infrastructure.
If you would like to extend Renode for your project or integrate it with your development workflow, reach out to us at contact@antmicro.com, and visit our dedicated offering page to learn more about Renode's capabilities and Antmicro's services.