Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rpi baremetal #121

Merged
merged 3 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ env:
CARGO_TERM_COLOR: always

jobs:
build:
build-and-test:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Build gb
run: cargo build --verbose --package gb
- name: Run tests
run: cargo test --verbose --workspace --exclude bcm_host
run: cargo test --verbose --package lib_gb
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ lib_*/Cargo.lock
Dependencies/
*.wav
*.bmp
*.img

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down
9 changes: 9 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ members = [
"gb",
"lib_gb",
"image_inter",
"bcm_host"
"bcm_host",
"baremetal"
]

[workspace.package]
Expand Down
81 changes: 72 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ The main goal of this project is to be able to play Pokemon on my own emulator.

**More will be added if neccessary (and by neccessary I mean if games I want to play will require them)**

## How to use
## Building

### Building
### Desktop

```shell
cargo build --release --features [optional_features]
cargo build --release --package gb --features [optional_features]
```
#### Optional features:
* `sdl` - Link to sdl2 (On by default)
Expand All @@ -32,7 +32,7 @@ On by default

> **Note** to turn off on by default features pass `--no-default-features` when building

### Key bindings:
#### Key bindings:

| Joypad | Keyboard |
| ---------- | ----------- |
Expand All @@ -45,17 +45,38 @@ On by default
| Dpad Left | Left arrow |
| Dpad Right | Right arrow |

### Running
### Raspberry Pi Baremetal (with ili9341 display and gpio buttons)

#### Desktop
1. Install the rust nightly toolchain for `armv7a-none-eabihf`:
```shell
rustup target add armv7a-none-eabihf --toolchain nightly
rustup +nightly component add rust-src
```

Unfurtuantly `armv7a-none-eabihf` is a [tier3](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-3) target for the Rust compiler so building for it requires the nightly toolchain - [source](https://stackoverflow.com/questions/67352828/how-to-build-for-tier-3-target-not-included-in-rustup-target-list)

> **Notice** Verify that you install the `armv7a-none-eabihf` target and not the `armv7a-none-eabi` target, as the later doesn't have support for hardware floats.

2. Install Cargo Binutils:
```shell
cargo install cargo-binutils
rustup component add llvm-tools-preview
```

3. Edit the relevant settings in `configuration.rs`
4. Run `build.sh` or `build.bat` which will compile and create an bootable image called `kernel7.img`

## Running

### Desktop
```sh
magenboy [path_to_rom] [other_optional_flags]
```

#### Raspberry Pi
### Raspberry Pi Desktop with peripherals
See - [RealMagenBoy](docs/RealMagenBoy.md)

### Optional flags
#### Optional flags

* `--file-audio` - Saves the audio to a file
* `--full-screen` - Full screen mode
Expand All @@ -66,6 +87,37 @@ Choose a game with the Joypad bindings (Dpad and A to confirm)
* `--mode [mahcine mode]` - Override the auto machine detection for the game (mode can be: `CGB` - Gameboy color | `DMG` - Original Gameboy | `ANY` - default)
* `--shutdown-rpi` - Requires `rpi` feature, shutdown the RPi upon shutdown of the program

### Raspberry Pi Baremetal

Currently only Raspberry Pi 4 is supported using the following instructions:
* Format a sd card and make a single `FAT32` partition called `boot`
* Copy the file `config.txt` to the root dir of the sd card
* Copy the following files from the [Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot) onto the SD card:
- [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat)
- [start4.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start4.elf)
- [bcm2711-rpi-4-b.dtb](https://github.com/raspberrypi/firmware/raw/master/boot/bcm2711-rpi-4-b.dtb)
* Copy `kernel7.img` onto the SD card
* Connect all the peripherals (ili9341 display and gpio buttons)
* Insert the SD card to the RPI4 and boot it

_**Note**: Should it not work on your RPi4, try renaming `start4.elf` to `start.elf` (without the 4)
on the SD card._

### QEMU

Currently Qemu doesn't support RPI4 in 32 bit mode, so in order to test it I added support for RPI2 mapping.
To change to RPI2 mode build with the `rpi2` feature and not the default `rpi4` feature.

running with qemu:
```shell
qemu-system-arm.exe -M raspi2b -serial null -serial mon:stdio -kernel path_to_elf
```

_**Note** Qemu takes the path to the elf generated by cargo not the image generated by binutils_
the UART output will be written to the console.

I think that not all the peripherals I use are implemented in QEMU so I used this mainly to debug boot and CPU initialization problems

## GameBoy

### Development Status
Expand Down Expand Up @@ -125,4 +177,15 @@ Choose a game with the Joypad bindings (Dpad and A to confirm)
- [Raspberry Pi docs](https://www.raspberrypi.com/documentation/computers/processors.html)
- [juj/fbcp-ili9341 as a refference](https://github.com/juj/fbcp-ili9341)
- [Raspberry Pi DMA programming in C](https://iosoft.blog/2020/05/25/raspberry-pi-dma-programming/)
- [Ili9341 docs](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf)
- [Ili9341 docs](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf)
#### BareMetal RaspberryPi
- [Bare-metal Boot Code for ARMv8-A](http://classweb.ece.umd.edu/enee447.S2021/baremetal_boot_code_for_ARMv8_A_processors.pdf)
- [Low performance Baremetal code Blog post](https://forums.raspberrypi.com/viewtopic.php?t=219212)
- [Raspberry-Pi-Multicode examples by LdB-ECM](https://github.com/LdB-ECM/Raspberry-Pi)
- [RaspberryPi official Linux fork](https://github.com/raspberrypi/linux)
- ARM official Docs
- [ARM Cortex-A72 manual](https://developer.arm.com/documentation/100095/0003)
- [ARMv7-A Architecture Reference Manual](https://developer.arm.com/documentation/ddi0406/cb/?lang=en)
- [ARMv8-A Architecture Reference Manual](https://developer.arm.com/documentation/ddi0487/ia/?lang=en)
- [ARMv8-A Registers](https://developer.arm.com/documentation/ddi0595/2021-12/AArch32-Registers/CCSIDR--Current-Cache-Size-ID-Register?lang=en)
- [ARMv7-A programmer Guide](https://developer.arm.com/documentation/den0013/latest/)
6 changes: 6 additions & 0 deletions baremetal/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build]
target = "armv7a-none-eabihf"
rustflags = [
"-Clink-arg=--script=./baremetal/link.ld",
"-Ctarget-feature=+virtualization"
alloncm marked this conversation as resolved.
Show resolved Hide resolved
]
17 changes: 17 additions & 0 deletions baremetal/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "baremetal"
version.workspace = true
authors.workspace = true
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4"
lib_gb = {path = "../lib_gb", features = ["u16pixel"]}
image_inter = {path = "../image_inter"}

[features]
default = ["rpi4"]
rpi4 = []
rpi2 = []
alloncm marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions baremetal/build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cargo +nightly b -r -Z build-std=core
rust-objcopy ../target/armv7a-none-eabihf/release/baremetal -O binary kernel7.img
5 changes: 5 additions & 0 deletions baremetal/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const LD_SCRIPT_PATH:&str = "link.ld";

fn main(){
println!("cargo:rerun-if-changed={}", LD_SCRIPT_PATH);
}
3 changes: 3 additions & 0 deletions baremetal/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# armv7a-none-eabihf is not supported automacticaly by rust so the nightly toolchain is neccessary to build the core library
cargo +nightly b -r -Z build-std=core
rust-objcopy ../target/armv7a-none-eabihf/release/baremetal -O binary kernel7.img
7 changes: 7 additions & 0 deletions baremetal/config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# configuration for the RPI
alloncm marked this conversation as resolved.
Show resolved Hide resolved
arm_64bit=0 # boot to 32 bit mode

# fast boot
boot_delay=0
disable_poe_fan=1
disable_splash=1
60 changes: 60 additions & 0 deletions baremetal/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* Place _start procedure at the entry address for RPI */
__rpi_32_phys_binary_load_addr = 0x8000;
__isr_table_addr = 0;
__stack_size = 0x100000; /* 1MB stack */
ENTRY(__rpi_32_phys_binary_load_addr) /* enry point */

SECTIONS
{
.isr_table (NOLOAD) :
{
. = __isr_table_addr;
/* allocate space for the table */
. = . + 0x40;
}
. = __rpi_32_phys_binary_load_addr;
.text :
{
KEEP(*(.text._start)) /*put _start first, `KEEP` disables linker optimizations*/
*(.text*)
}
/*readonly data - readonly global variables*/
.rodata :
{
*(.rodata*)
}
/*global variables*/
.data :
{
*(.data*)
}
.stack (NOLOAD) : ALIGN(16)
{
. = . + __stack_size;
__cpu0_stack_start = .; /* stack grows from high address to low address */
}
/*bss must be at the end of the linker script in order to keep the image small (otherwise objcopy will gap the space between bss and the next section)*/
/*uninitialized global variables*/
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*)
__bss_end = .;
}
/* uncached memory - used by drivers and devices */
/* Since L1 memory map entry is 1MB, make sure it's alligned correctly*/
.uncached (NOLOAD) : ALIGN(0x100000)
{
__uncached_data_start = .;
__cached_data_map_size = __uncached_data_start / 0x100000;
*(.uncached*)
}

/* Remove those sections from the final binary */
/DISCARD/ :
{
*(.ARM.attributes)
*(.ARM.exidx) /* Used for stack unwinding - not relevant for now */
*(.comment) /* comments about the compiler and linker - not intresting */
}
}
18 changes: 18 additions & 0 deletions baremetal/src/boot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use core::arch::{global_asm, asm};

#[no_mangle]
static PERIPHERALS_BASE_ADDRESS:u32 = crate::peripherals::PERIPHERALS_BASE_ADDRESS as u32;

global_asm!(include_str!("boot_armv7a.s"));

extern "C"{
// declared at startup assembly file
pub fn hang_led()->!;
}

pub fn get_cpu_execution_mode()->u32{
let mut mode:u32;
unsafe{asm!("mrs {r}, cpsr", r = out(reg) mode)};
// only the first 5 bits are relevant for the mode
return mode & 0b1_1111;
}
Loading