gba/src/lib.rs

322 lines
8.7 KiB
Rust
Raw Normal View History

#![cfg_attr(not(test), no_std)]
2018-12-18 20:05:59 +11:00
#![feature(asm)]
#![feature(cfg_target_vendor)]
2018-12-18 11:00:22 +11:00
#![allow(clippy::cast_lossless)]
2018-12-08 19:53:37 +11:00
#![deny(clippy::float_arithmetic)]
2018-12-31 19:07:33 +11:00
//#![warn(missing_docs)]
//! This crate helps you write GBA ROMs.
//!
2018-12-18 11:00:22 +11:00
//! ## 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.
pub(crate) use gba_proc_macro::phantom_fields;
2018-12-26 08:45:51 +11:00
2018-12-18 11:00:22 +11:00
/// Assists in defining a newtype wrapper over some base type.
///
/// Note that rustdoc and derives are all the "meta" stuff, so you can write all
/// of your docs and derives in front of your newtype in the same way you would
/// for a normal struct. Then the inner type to be wrapped it name.
///
2018-12-30 14:17:48 +11:00
/// The macro _assumes_ that you'll be using it to wrap numeric types and that
/// it's safe to have a `0` value, so it automatically provides a `const fn`
/// method for `new` that just wraps `0`. Also, it derives Debug, Clone, Copy,
/// Default, PartialEq, and Eq. If all this is not desired you can add `, no
/// frills` to the invocation.
2018-12-18 11:00:22 +11:00
///
/// Example:
/// ```
/// newtype! {
/// /// Records a particular key press combination.
/// KeyInput, u16
/// }
2018-12-30 14:17:48 +11:00
/// newtype! {
/// /// You can't derive most stuff above array size 32, so we add
2018-12-30 16:39:53 +11:00
/// /// the `, no frills` modifier to this one.
2018-12-30 14:17:48 +11:00
/// BigArray, [u8; 200], no frills
/// }
2018-12-18 11:00:22 +11:00
/// ```
#[macro_export]
macro_rules! newtype {
2018-12-26 10:45:10 +11:00
($(#[$attr:meta])* $new_name:ident, $v:vis $old_name:ty) => {
2018-12-18 11:00:22 +11:00
$(#[$attr])*
2018-12-30 14:17:48 +11:00
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2018-12-18 11:00:22 +11:00
#[repr(transparent)]
2018-12-26 10:45:10 +11:00
pub struct $new_name($v $old_name);
2018-12-18 11:00:22 +11:00
impl $new_name {
/// A `const` "zero value" constructor
pub const fn new() -> Self {
$new_name(0)
}
}
};
2018-12-26 10:45:10 +11:00
($(#[$attr:meta])* $new_name:ident, $v:vis $old_name:ty, no frills) => {
2018-12-18 11:00:22 +11:00
$(#[$attr])*
#[repr(transparent)]
2018-12-26 10:45:10 +11:00
pub struct $new_name($v $old_name);
2018-12-18 11:00:22 +11:00
};
}
2018-12-30 16:39:53 +11:00
/// Assists in defining a newtype that's an enum.
///
/// First give `NewType = OldType,`, then define the tags and their explicit
/// values with zero or more entries of `TagName = base_value,`. In both cases
/// you can place doc comments or other attributes directly on to the type
/// declaration or the tag declaration.
///
/// The generated enum will get an appropriate `repr` attribute as well as Debug, Clone, Copy,
///
/// Example:
/// ```
/// newtype_enum! {
/// /// The Foo
/// Foo = u16,
/// /// The Bar
/// Bar = 0,
/// /// The Zap
/// Zap = 1,
/// }
/// ```
2018-12-30 14:17:48 +11:00
#[macro_export]
macro_rules! newtype_enum {
(
$(#[$struct_attr:meta])*
$new_name:ident = $old_name:ident,
$($(#[$tag_attr:meta])* $tag_name:ident = $base_value:expr,)*
) => {
$(#[$struct_attr])*
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr($old_name)]
pub enum $new_name {
$(
$(#[$tag_attr])*
$tag_name = $base_value,
)*
}
};
}
2018-12-21 12:08:54 +11:00
pub mod base;
pub(crate) use self::base::*;
2018-12-30 14:17:48 +11:00
2018-12-17 09:17:30 +11:00
pub mod bios;
2018-12-30 14:17:48 +11:00
2018-12-30 16:39:53 +11:00
pub mod iwram;
pub mod ewram;
2018-12-30 14:17:48 +11:00
pub mod io;
2018-12-30 14:17:48 +11:00
2018-12-26 08:45:51 +11:00
pub mod palram;
2018-12-30 14:17:48 +11:00
2018-12-27 17:13:10 +11:00
pub mod vram;
2018-12-30 14:17:48 +11:00
pub mod oam;
pub mod rom;
pub mod sram;
pub mod mgba;
2019-01-13 07:42:18 +11:00
extern "C" {
/// This marks the end of the `.data` and `.bss` sections in IWRAM.
///
/// Memory in IWRAM _before_ this location is not free to use, you'll trash
/// your globals and stuff. Memory here or after is freely available for use
/// (careful that you don't run into your own stack of course).
static __bss_end: u8;
}
newtype! {
/// A color on the GBA is an RGB 5.5.5 within a `u16`
2018-12-30 14:17:48 +11:00
#[derive(PartialOrd, Ord, Hash)]
Color, u16
}
impl Color {
/// Constructs a color from the channel values provided (should be 0..=31).
///
/// No actual checks are performed, so illegal channel values can overflow
/// into each other and produce an unintended color.
pub const fn from_rgb(r: u16, g: u16, b: u16) -> Color {
Color(b << 10 | g << 5 | r)
}
2018-12-24 09:10:14 +11:00
/// Does a left rotate of the bits.
///
/// This has no particular meaning but is a wild way to cycle colors.
pub const fn rotate_left(self, n: u32) -> Color {
Color(self.0.rotate_left(n))
}
}
//
// After here is totally unsorted nonsense
//
/// Performs unsigned divide and remainder, gives None if dividing by 0.
pub fn divrem_u32(numer: u32, denom: u32) -> Option<(u32, u32)> {
// TODO: const this? Requires const if
if denom == 0 {
None
} else {
Some(unsafe { divrem_u32_unchecked(numer, denom) })
}
}
/// Performs divide and remainder, no check for 0 division.
///
/// # Safety
///
/// If you call this with a denominator of 0 the result is implementation
/// defined (not literal UB) including but not limited to: an infinite loop,
/// panic on overflow, or incorrect output.
pub unsafe fn divrem_u32_unchecked(numer: u32, denom: u32) -> (u32, u32) {
// TODO: const this? Requires const if
if (numer >> 5) < denom {
divrem_u32_simple(numer, denom)
} else {
divrem_u32_non_restoring(numer, denom)
}
}
/// The simplest form of division. If N is too much larger than D this will be
/// extremely slow. If N is close enough to D then it will likely be faster than
/// the non_restoring form.
fn divrem_u32_simple(mut numer: u32, denom: u32) -> (u32, u32) {
// TODO: const this? Requires const if
let mut quot = 0;
while numer >= denom {
numer -= denom;
quot += 1;
}
(quot, numer)
}
/// Takes a fixed quantity of time based on the bit width of the number (in this
/// case 32).
fn divrem_u32_non_restoring(numer: u32, denom: u32) -> (u32, u32) {
// TODO: const this? Requires const if
let mut r: i64 = numer as i64;
let d: i64 = (denom as i64) << 32;
let mut q: u32 = 0;
let mut i = 1 << 31;
while i > 0 {
if r >= 0 {
q |= i;
r = 2 * r - d;
} else {
r = 2 * r + d;
}
i >>= 1;
}
q -= !q;
if r < 0 {
q -= 1;
r += d;
}
r >>= 32;
// TODO: remove this once we've done more checks here.
debug_assert!(r >= 0);
debug_assert!(r <= core::u32::MAX as i64);
(q, r as u32)
}
/// Performs signed divide and remainder, gives None if dividing by 0 or
/// computing `MIN/-1`
pub fn divrem_i32(numer: i32, denom: i32) -> Option<(i32, i32)> {
if denom == 0 || (numer == core::i32::MIN && denom == -1) {
None
} else {
Some(unsafe { divrem_i32_unchecked(numer, denom) })
}
}
/// Performs signed divide and remainder, no check for 0 division or `MIN/-1`.
///
/// # Safety
///
/// * If you call this with a denominator of 0 the result is implementation
/// defined (not literal UB) including but not limited to: an infinite loop,
/// panic on overflow, or incorrect output.
/// * If you call this with `MIN/-1` you'll get a panic in debug or just `MIN`
/// in release (which is incorrect), because of how twos-compliment works.
pub unsafe fn divrem_i32_unchecked(numer: i32, denom: i32) -> (i32, i32) {
// TODO: const this? Requires const if
let unsigned_numer = numer.abs() as u32;
let unsigned_denom = denom.abs() as u32;
let opposite_sign = (numer ^ denom) < 0;
let (udiv, urem) = if (numer >> 5) < denom {
divrem_u32_simple(unsigned_numer, unsigned_denom)
} else {
divrem_u32_non_restoring(unsigned_numer, unsigned_denom)
};
match (opposite_sign, numer < 0) {
(true, true) => (-(udiv as i32), -(urem as i32)),
(true, false) => (-(udiv as i32), urem as i32),
(false, true) => (udiv as i32, -(urem as i32)),
(false, false) => (udiv as i32, urem as i32),
}
}
/*
#[cfg(test)]
mod tests {
use super::*;
use quickcheck::quickcheck;
// We have an explicit property on the non_restoring division
quickcheck! {
fn divrem_u32_non_restoring_prop(num: u32, denom: u32) -> bool {
if denom > 0 {
divrem_u32_non_restoring(num, denom) == (num / denom, num % denom)
} else {
true
}
}
}
// We have an explicit property on the simple division
quickcheck! {
fn divrem_u32_simple_prop(num: u32, denom: u32) -> bool {
if denom > 0 {
divrem_u32_simple(num, denom) == (num / denom, num % denom)
} else {
true
}
}
}
// Test the u32 wrapper
quickcheck! {
fn divrem_u32_prop(num: u32, denom: u32) -> bool {
if denom > 0 {
divrem_u32(num, denom).unwrap() == (num / denom, num % denom)
} else {
divrem_u32(num, denom).is_none()
}
}
}
// test the i32 wrapper
quickcheck! {
fn divrem_i32_prop(num: i32, denom: i32) -> bool {
if denom == 0 || num == core::i32::MIN && denom == -1 {
divrem_i32(num, denom).is_none()
} else {
divrem_i32(num, denom).unwrap() == (num / denom, num % denom)
}
}
}
}
*/