c2fj — C to FlipJump¶
A C-to-FlipJump compiler that uses RISC-V as an intermediate representation.
C source → RISC-V → FlipJump → .fjm binary
picolibc opcode→macro fj interpreter
Install¶
pip install c2fj
sudo apt install picolibc-riscv64-unknown-elf
Linux only; Python 3.8–3.12 per upstream pyproject.toml. The picolibc apt package provides the RISC-V C library + cross-compiler.
Run¶
python3 c2fj.py file.c
That compiles your C source through the full pipeline (C → ELF → .fj fragments → .fjm) and immediately runs it through the FlipJump interpreter. The intermediate artifacts are written to the build directory (--build-dir overrides where).
For multi-file C projects, drive the compilation with a Makefile. The custom linker script must define three symbols: _stack_end, _sdata, and __heap_start.
How it works¶
C → RISC-V — uses picolibc as a freestanding C library, with custom syscall implementations for I/O. Special assembly patterns in picolibc trigger compiler-recognised intrinsics.
RISC-V → FlipJump — each RISC-V opcode is implemented as an optimised FlipJump macro (30–40 ops each). A jump table (
jmp.fj) resolves dynamic addresses; memory loads/stores go throughmem.fj.Execution — run the resulting
.fjmwith thefjinterpreter.
Useful flags¶
Flag |
Purpose |
|---|---|
|
Insert breakpoints at C source lines for the interpreter’s debugger. |
|
Step one FlipJump op at a time. |
|
Bundle every generated |
|
Stop after N FlipJump operations (useful for runaway programs). |
|
Override where intermediate |
Caveats¶
Programs run much slower than native C. Every RISC-V op becomes 30+ FlipJump ops, and every FlipJump op is two memory accesses on top of the host’s actual cycle.
Not all of libc compiles — picolibc covers the freestanding subset.
Floating point depends on the chosen libc backend; integer-only programs are the smoothest path.
See also¶
The FlipJump IDE — interactive runtime, ideal for stepping through compiled output.
Standard Library — what the c2fj-generated FlipJump code relies on under the hood.