Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/zlfn/rust-gb

Compile Rust code to GBZ80 (Gameboy Z80)
https://github.com/zlfn/rust-gb

Last synced: about 2 months ago
JSON representation

Compile Rust code to GBZ80 (Gameboy Z80)

Awesome Lists containing this project

README

        

# Rust-GB
Compile Rust code to GBZ80 (Work in Progress)
You can find ROM builds of examples in [release](https://github.com/zlfn/rust-gb/releases/tag/v0.0.1-alpha)

![image](https://github.com/user-attachments/assets/90c049f7-7317-44c9-9c73-a7865c78b24e)
^ `filltest` example of GBDK-2020, ported to Rust.

## How is this possible?
1. The Rust compiler can generate LLVM-IR for the ATMega328 processor. (which powers Arduino)
2. LLVM-IR can be converted to C code using [llvm-cbe](https://github.com/JuliaHubOSS/llvm-cbe).
3. The C code can then be compiled to Z80 Assembly using [sdcc](https://sdcc.sourceforge.net/).
4. Z80 Assembly can be assembled into GBZ80 object code with [sdasgb](https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_supported_consoles.html).
5. The GBZ80 object code can be linked with GBDK libraries and built into a Game Boy ROM using [lcc](https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_toolchain.html#lcc).

I referred to [z80-babel](https://github.com/MartinezTorres/z80_babel) for steps 1–3, and used [gbdk-2020](https://github.com/gbdk-2020/gbdk-2020) for steps 4–5.

## Why use Rust instead of C or ASM?
1. Rust provides higher-level and better grammer than C.
2. Rust's memory stability and strict types help you avoid to write incorrect code (even on a small device).
3. Putting everything aside, it's fun!

## Goal
My goal is to develop a Game Boy Development Kit that enables the creation of Game Boy games using Rust.

Thanks to GBDK, Z80 Assembly generated from Rust can call GBDK's low-level library functions (such as `delay`, `waitpad`, etc.).

My task is to wrap these functions in high-level Rust abstractions.

## Dependencies
* rust
* avr-gcc
* avr-libc
* llvm
* llvm-cbe
* sdcc

This project is still a work in progress, and I haven't tested it outside of my development environment.

Dependencies may change as the project evolves.

## Build
I do not recommend that you build this project now. because this is WIP and I'm still testing many things.

But if you want to do it, Here is the description below.

1. Install all dependencies in your linux (Use WSL for Windows)
2. Build llvm-cbe in `./ext` directory.
follow [llvm-cbe](https://github.com/JuliaHubOSS/llvm-cbe)'s instruction to build it.
the path is `./ext/llvm-project/llvm/build/bin/llvm-cbe`
3. Execute `cargo build --release` in `./ext/rust-deps`
4. Now, `cargo build-rom` (where the `./src` directory is located) will build your GB ROM to `./out/main.gb`

```bash
# build GB ROM from Rust code
cargo build-rom

# build GB ROM from LLVM-IR
cargo llvm-rom
# ... from C code
cargo c-rom
# ... from ASM code
cargo asm-romm
```

## Can do and Can't do
### Can do
* Call inline GB ASM functions in Rust
* Call the GBDK library in Rust
* Use `core` or `alloc` libraries of Rust
### Can't do
* Some Rust functions use fast calling convention which not supported in `LLVM-CBE`. (`alloc::Vec` or `assert_eq!` etc. I'm finding a solution for it.
* External crates are likely not supported.

## Build chain Description
### Rust bundling
Rust codes in `./source` bundled in one .rs file by [rust-bundler-cp](https://github.com/Endle/rust-bundler-cp)
### Rust -> LLVM-IR
Bundled Rust code is compiled to target `avr-unknown-gnu-atmega328`.
This will provide 8-bit compatibility for z80.

Keep compatibility through the replacement of new function or polyfill.
### LLVM-IR -> C
LLVM-CBE compile LLVM-IR to C code.
Unfortunetly, LLVM-CBE do not support some calling convention generated by Rust.
So, Some features from rust (like `alloc::Vec`) can not be used.

Also, I'm considering If it can be replaced with [llvm-gbz80](https://github.com/Bevinsky/llvm-gbz80)
### C post-processing
The generated C code is for GCC. Therefore, it goes through post-processing before it is entered into SDCC.

Use the tree-sitter to parse the C code, and replace or add the required codes.
### C -> ASM
SDCC compile C code for GBZ80 (`sm83`)
### ASM -> ROM
I used GBDK's build chain for this. GBDK's `lcc` link ASM with GBDK libraries and build a complete Gameboy ROM file.