Skip to content

Commit

Permalink
Merge in related repos, and no more building the compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
Seeker14491 committed Oct 27, 2021
1 parent a0e9ab8 commit f6001b4
Show file tree
Hide file tree
Showing 25 changed files with 743 additions and 701 deletions.
12 changes: 12 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[build]
target = "arduboy.json"

[profile.release]
codegen-units = 1
lto = "fat"
opt-level = "z"
panic = "abort"

[unstable]
build-std = ["core", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ArduboyRustHost/lib/*.a
/target
/.idea
6 changes: 6 additions & 0 deletions ArduboyRustHost/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
lib/*.a
67 changes: 0 additions & 67 deletions ArduboyRustHost/.travis.yml

This file was deleted.

14 changes: 7 additions & 7 deletions ArduboyRustHost/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
21 changes: 0 additions & 21 deletions ArduboyRustHost/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,6 @@ Arduboy2 arduboy;
ArduboyTones sound(arduboy.audio.enabled);

extern "C" {
int __ashlsi3 (int a, int b) {
return a << b;
}

int __ashrsi3 (int a, int b) {
return a >> b;
}

int __lshrsi3 (int a, int b) {
return (unsigned int) a >> b;
}

unsigned long long __divmodti4 (long long a, long long b, long long *c) {
*c = a % b;
return a / b;
}

long mod_i32(long a, long b) {
return a % b;
}

long arduino_random_between(long min, long max) {
return random(min, max);
}
Expand Down
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["arduboy-rs", "examples/pong"]
96 changes: 20 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,29 @@

Running Rust on the [Arduboy](https://arduboy.com/) miniature game system.

## Building Rust with AVR support
## Creating and building an Arduboy crate

Rust does not currently officially support the AVR architecture the Arduboy uses, though it hopefully will at some point ([see this issue](https://github.com/rust-lang/rust/issues/44052)). However, there is [a fork](https://github.com/avr-rust/rust) of the compiler with AVR support, which we’ll use.
Prerequisite: rustup

### Prerequisites
The idea is to compile our Rust code as a static library which can then be linked into an Arduino C++ project.

You will need the following to build the compiler:

- Enough disk space. I don’t recall exactly how much is needed, but 120GB should be enough.
- Enough free system memory. 8GB free should be enough.
- The dependencies listed [here](https://github.com/rust-lang/rust/#installing-from-source).

### Building

1. Get the compiler source files
```
mkdir avr
cd avr
git clone https://github.com/avr-rust/rust.git -b avr-support --recursive
cd rust
```

2. Place the `config.toml` from this repo inside the current directory (the `rust` folder). On Windows, you might want to uncomment and set the `build =` `"``…``"` field to `x86_64-pc-windows-gnu` if you want to build using the GNU ABI.

3. Start the build using

```
python x.py build
```

This will take a while.

4. Assuming the build finished successfully, copy cargo from the `stage0` folder to the `stage2` folder:

```
cp build/<target-triple>/stage0/bin/cargo[.exe] build/<target-triple>/stage2/bin/
```

5. The only files we need to keep are the `build/<target-triple>/stage2` folder and the `src` folder. You might want to move these folders to the `avr` folder we made at the start. You can delete everything else in the current `rust` folder.

6. Register the toolchain with rustup (adjust the path if you moved/renamed the `stage2` folder):

```
rustup toolchain link avr build/<target-triple>/stage2
```

## Building a crate

The idea is to compile our Rust code as a static library, and then link it from an Arduino C++ project.

1. Install `[cargo-xbuild](https://crates.io/crates/cargo-xbuild)` if you don’t have it:
1. Create a new library crate:

```
cargo install cargo-xbuild
cargo new --lib my-crate
cd my-crate
```

2. Create a new library crate

3. Add the following fields to your crate’s `Cargo.toml`:
2. Add the following to your crate’s `Cargo.toml`:

```toml
[lib]
crate-type = ["staticlib"]

[profile.release]
codegen-units = 1
lto = true
opt-level = "z"
panic = "abort"
```

4. Place the `arduboy.json` from this repo in your crate root.
3. From this repo, copy the `.cargo` directory and the `arduboy.json` and `rust-toolchain.toml` files all into your crate's root directory.

5. Replace the contents of your `lib.rs` with the following:
4. Replace the contents of your `lib.rs` with the following:

```rust
#![no_std]
Expand All @@ -92,22 +41,20 @@ pub unsafe extern "C" fn loop_() {
}
```

6. Set the environment variable `XARGO_RUST_SRC` to the `src` folder of the `avr-rust` repo you cloned above.

7. Finally, compile the crate:
5. Finally, compile the crate:
```
cargo +avr xb --target=arduboy.json --release
cargo build --release
```

If the crate compiles successfully, the built static library will be at `target/arduboy/release/lib*.a`.
If the crate compiles successfully, the built static library will be at `./target/arduboy/release/lib*.a`. Of course, this code doesn't do anything yet; the `arduboy-rs` directory in this repo is a rust library that provides some basic functionality you can use. See the `examples` directory for example use of the crate.

## Linking the static library to an Arduino C++ project
## Linking the static library to the Arduino C++ project

For creating the Arduino C++ project, I recommend using [PlatformIO](https://platformio.org/).
Prerequisite: [PlatformIO IDE](https://platformio.org/install/ide) or [PlatformIO Core](https://platformio.org/install/cli)

### Using PlatformIO (recommended)
The `ArduboyRustHost` directory in this repo contains a [PlatformIO](https://platformio.org/) project that acts as a proxy between Rust and any C++ Arduboy libraries we wish to use. If you look at `ArduboyRustHost/src/main.cpp`, you'll see it's just a bunch of function re-exports in an `extern "C"` block. The `arduboy-rs` directory in this repo is a rust library crate that consumes those re-exports, providing an API we can use in our crate from before.

After creating the PlatformIO project, to link in our static library, use the `build_flags` setting in the project `platformio.ini`. Assuming you placed the built static library file `lib*.a` inside the project `lib` folder, you would add `-L lib -l lib*` to the build flags. An example of how the `platformio.ini` might look (in this case the static library file is called `libdig.a`):
To link in our static library, copy the static library we built (`./target/arduboy/release/lib*.a`) over to the directory `ArduboyRustHost/lib`. Then, modify the `build_flags` setting in `ArduboyRustHost/platformio.ini` to reflect the name of the file we copied. An example of how the `platformio.ini` might look (in this case the static library file is called `libdig.a`):

```ini
[env:arduboy]
Expand All @@ -123,16 +70,13 @@ lib_deps =
ArduboyTones@^1.0.3
```

### Using the Arduino IDE (hacky, not recommended)
The `ArduboyRustHost` project can then be built and uploaded to an Arduboy as usual, either through the PlatformIO IDE, or through the commandline through `pio` (ran from inside the `ArduboyRustHost` directory:

I edited `%LOCALAPPDATA%/Arduino15/packages/arduino/hardware/avr/1.8.1/platform.txt` and added the path to the built `*.a` file in this section like this:
To build: `pio run`

```
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" C:/Users/seekr/projects/rust/Arduboy/arduboy-hello-rs/target/arduboy/release/libhello.a "-L{build.path}" -lm
```
To build and upload: `pio run -t upload`

Note that this will apply to all sketches, so remove it when compiling other sketches.
To clean build files: `pio run -t clean`

---

Expand Down
9 changes: 9 additions & 0 deletions arduboy-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "arduboy"
version = "0.1.0"
authors = ["Brian Bowman <[email protected]>"]
license = "MIT OR Apache-2.0"
edition = "2018"

[dependencies]
panic-halt = "0.2"
5 changes: 5 additions & 0 deletions arduboy-rs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# arduboy-rs

A Rust library that exposes Arduboy functionality.

Crates that use this library must compile to a static library which is then linked into the PlatformIO project provided in the `ArduboyRust` directory of this repo.
7 changes: 7 additions & 0 deletions arduboy-rs/src/c/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use self::types::*;

pub mod types;

extern "C" {
pub fn strlen(cstr: *const c_char) -> c_size_t;
}
34 changes: 34 additions & 0 deletions arduboy-rs/src/c/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// https://gcc.gnu.org/wiki/avr-gcc#Type_Layout

#[allow(non_camel_case_types)]
pub type c_char = i8;

#[allow(non_camel_case_types)]
pub type c_uchar = u8;

#[allow(non_camel_case_types)]
pub type c_size_t = u16;

#[allow(non_camel_case_types)]
pub type c_int = i16;

#[allow(non_camel_case_types)]
pub type c_uint = u16;

#[allow(non_camel_case_types)]
pub type c_long = i32;

#[allow(non_camel_case_types)]
pub type c_ulong = u32;

#[allow(non_camel_case_types)]
pub type c_longlong = i64;

#[allow(non_camel_case_types)]
pub type c_ulonglong = u64;

#[allow(non_camel_case_types)]
pub type c_float = f32;

#[allow(non_camel_case_types)]
pub type c_double = f32;
Loading

0 comments on commit f6001b4

Please sign in to comment.