2018-11-15 13:49:00 +11:00
|
|
|
#![cfg_attr(not(test), no_std)]
|
2018-11-18 11:14:42 +11:00
|
|
|
#![cfg_attr(not(test), feature(asm))]
|
2018-11-14 06:47:52 +11:00
|
|
|
#![warn(missing_docs)]
|
2018-11-20 22:10:48 +11:00
|
|
|
#![allow(clippy::cast_lossless)]
|
2018-11-14 06:47:52 +11:00
|
|
|
|
|
|
|
//! This crate helps you write GBA ROMs.
|
|
|
|
//!
|
|
|
|
//! # SAFETY POLICY
|
|
|
|
//!
|
|
|
|
//! Some parts of this crate are safe wrappers around unsafe operations. This is
|
|
|
|
//! good, and what you'd expect from a Rust crate.
|
|
|
|
//!
|
|
|
|
//! However, the safe wrappers all assume that you will _only_ attempt to
|
|
|
|
//! execute this crate on a GBA or in a GBA Emulator.
|
|
|
|
//!
|
|
|
|
//! **Do not** use this crate in programs that aren't running on the GBA. If you
|
|
|
|
//! do, it's a giant bag of Undefined Behavior.
|
2018-11-15 13:49:00 +11:00
|
|
|
//!
|
|
|
|
//! # TESTING POLICY
|
|
|
|
//!
|
|
|
|
//! It is the intent of the crate authors that as much of the crate as possible
|
|
|
|
//! be written so that you can use `cargo test` for at least some parts of your
|
|
|
|
//! code without everything exploding instantly. To that end, where possible we
|
|
|
|
//! attempt to use `cfg` flags to make things safe for `cargo test`. Hopefully
|
|
|
|
//! we got it all.
|
2018-11-14 06:47:52 +11:00
|
|
|
|
|
|
|
pub mod core_extras;
|
|
|
|
pub(crate) use crate::core_extras::*;
|
|
|
|
|
|
|
|
pub mod io_registers;
|
|
|
|
|
|
|
|
pub mod video_ram;
|
2018-11-15 19:23:04 +11:00
|
|
|
pub(crate) use crate::video_ram::*;
|
|
|
|
|
2018-11-14 06:47:52 +11:00
|
|
|
/// Combines the Red, Blue, and Green provided into a single color value.
|
|
|
|
pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
|
|
|
|
blue << 10 | green << 5 | red
|
|
|
|
}
|
2018-11-15 19:23:04 +11:00
|
|
|
|
|
|
|
/// BIOS Call: Div (GBA SWI 0x06).
|
|
|
|
///
|
2018-11-16 18:39:47 +11:00
|
|
|
/// Gives just the DIV output of `numerator / denominator`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If `denominator` is 0.
|
|
|
|
#[inline]
|
|
|
|
pub fn div(numerator: i32, denominator: i32) -> i32 {
|
|
|
|
div_modulus(numerator, denominator).0
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BIOS Call: Div (GBA SWI 0x06).
|
|
|
|
///
|
|
|
|
/// Gives just the MOD output of `numerator / denominator`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If `denominator` is 0.
|
|
|
|
#[inline]
|
|
|
|
pub fn modulus(numerator: i32, denominator: i32) -> i32 {
|
|
|
|
div_modulus(numerator, denominator).1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BIOS Call: Div (GBA SWI 0x06).
|
|
|
|
///
|
|
|
|
/// Gives both the DIV and MOD output of `numerator / denominator`.
|
2018-11-15 19:23:04 +11:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If `denominator` is 0.
|
|
|
|
#[inline]
|
2018-11-16 18:39:47 +11:00
|
|
|
pub fn div_modulus(numerator: i32, denominator: i32) -> (i32, i32) {
|
2018-11-15 19:23:04 +11:00
|
|
|
assert!(denominator != 0);
|
2018-11-18 11:14:42 +11:00
|
|
|
#[cfg(not(test))]
|
|
|
|
{
|
|
|
|
let div_out: i32;
|
|
|
|
let mod_out: i32;
|
|
|
|
unsafe {
|
|
|
|
asm!(/* assembly template */ "swi 0x06"
|
2018-11-15 19:23:04 +11:00
|
|
|
:/* output operands */ "={r0}"(div_out), "={r1}"(mod_out)
|
|
|
|
:/* input operands */ "{r0}"(numerator), "{r1}"(denominator)
|
|
|
|
:/* clobbers */ "r3"
|
|
|
|
:/* options */
|
|
|
|
);
|
2018-11-18 11:14:42 +11:00
|
|
|
}
|
|
|
|
(div_out, mod_out)
|
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
|
|
{
|
|
|
|
(numerator / denominator, numerator % denominator)
|
2018-11-15 19:23:04 +11:00
|
|
|
}
|
|
|
|
}
|