felix86 25.08

A major milestone for felix86 was reached this month!

Browsers

We were able to run the Chromium browser under felix86!

You may be wondering: why would anyone want to do that?

The Linux version of Steam, running on RISC-V with felix86

A lot of modern apps use some kind of embedded version of Chromium. This ranges from the Windows Start Menu to Discord to Steam.

But Steam was always a huge goal for felix86. It has become the de facto launcher for games. Being able to launch games that use Steam DRM is great and allows us to test a wide variety of titles.

Steam itself is a 32-bit app. It uses a separate 64-bit tool called the steamwebhelper to render the GUI using the Chromium Embedded Framework. It also uses a tool called pressure-vessel for containerization. It does some tricky stuff with mounts and pivot_root.

If you’d like to try Steam, check out the Steam setup guide.

Installation guide

There’s also a quick installation guide for felix86 and Steam:

Optimizations

Most of the work this month was on getting Steam to work. However, we also optimized a few instructions.

One of the more interesting optimizations we made was the fusing of cmp instructions.

On RISC-V, if you want to check if, for example, register A is less than register B, you use the slt instruction.

On x86, you use the cmp instruction. The cmp instruction does a generic comparison between two registers and sets the flags accordingly. If you wanted to then set a register if A is less than B, you’d use the setl instruction after the cmp. The real operation of the setl instruction is checking if the overflow flag is not equal with the negative flag.

RISC-V doesn’t have flags, so felix86 computes them in software. This is expensive, particularly for the overflow flag, which takes numerous instructions to calculate. Luckily, cmp has no side-effects other than flags. If we know that the flags are only used for the setl and then overwritten, we could emit the cmp and setl combo as a single slt RISC-V instruction.

This is currently only done for cmp and cmovcc, but in the future we will expand it to work with setcc. The most used combo would probably be cmp and jcc, but supporting this would require analyzing more than one block at once, which we currently don’t do.

It should be noted that this optimization only works if the cmp is immediately followed by the instruction that uses the resulting flags. This is usually the case, but it’s possible for a compiler to emit instructions that don’t modify the flags between the two instructions. If deemed necessary, we could fuse cmp instructions even if the instruction that uses the flags is further down the line.

This optimization is currently disabled by default as it needs more testing. To enable it, run export FELIX86_FUSE_OPCODES=1.


Thanks for reading this post.

If you like this project, please give us a star on Github: https://github.com/OFFTKP/felix86

Written on August 1, 2025