2018-12-20 14:58:41 +11:00
|
|
|
#![cfg_attr(not(test), no_std)]
|
2018-12-18 20:05:59 +11:00
|
|
|
#![feature(asm)]
|
2019-01-03 16:43:52 +11:00
|
|
|
#![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)]
|
2019-02-13 19:47:25 +11:00
|
|
|
#![warn(missing_docs)]
|
2018-11-14 06:47:52 +11:00
|
|
|
|
|
|
|
//! This crate helps you write GBA ROMs.
|
|
|
|
//!
|
2018-12-18 11:00:22 +11:00
|
|
|
//! ## SAFETY POLICY
|
2018-11-14 06:47:52 +11:00
|
|
|
//!
|
|
|
|
//! 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-12-29 18:06:08 +11:00
|
|
|
pub(crate) use gba_proc_macro::phantom_fields;
|
2019-02-12 15:59:17 +11:00
|
|
|
pub(crate) use voladdress::{read_only::ROVolAddress, VolAddress, VolBlock};
|
2018-12-26 08:45:51 +11:00
|
|
|
|
2019-02-13 19:47:25 +11:00
|
|
|
pub mod macros;
|
2018-12-30 14:17:48 +11:00
|
|
|
|
2018-12-21 12:08:54 +11:00
|
|
|
pub mod 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
|
|
|
|
2018-12-21 10:15:23 +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-24 08:45:38 +11:00
|
|
|
|
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).
|
2019-02-10 06:50:00 +11:00
|
|
|
///
|
|
|
|
/// The actual value is unimportant, you just want to use the _address of_
|
|
|
|
/// this location as the start of your IWRAM usage.
|
2019-02-10 08:35:48 +11:00
|
|
|
pub static __bss_end: u8;
|
2019-01-13 07:42:18 +11:00
|
|
|
}
|
|
|
|
|
2018-12-24 08:45:38 +11:00
|
|
|
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)]
|
2019-02-13 19:47:25 +11:00
|
|
|
Color, pub u16
|
2018-12-24 08:45:38 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// After here is totally unsorted nonsense
|
|
|
|
//
|
2018-12-20 14:58:41 +11:00
|
|
|
|
|
|
|
/// Performs unsigned divide and remainder, gives None if dividing by 0.
|
|
|
|
pub fn divrem_u32(numer: u32, denom: u32) -> Option<(u32, u32)> {
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: const this? Requires const if
|
2018-12-20 14:58:41 +11:00
|
|
|
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) {
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: const this? Requires const if
|
2018-12-20 14:58:41 +11:00
|
|
|
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) {
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: const this? Requires const if
|
2018-12-20 14:58:41 +11:00
|
|
|
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) {
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: const this? Requires const if
|
2018-12-20 14:58:41 +11:00
|
|
|
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;
|
|
|
|
}
|
2018-12-21 10:15:23 +11:00
|
|
|
q -= !q;
|
2018-12-20 14:58:41 +11:00
|
|
|
if r < 0 {
|
2018-12-21 10:15:23 +11:00
|
|
|
q -= 1;
|
|
|
|
r += d;
|
2018-12-20 14:58:41 +11:00
|
|
|
}
|
2018-12-21 10:15:23 +11:00
|
|
|
r >>= 32;
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: remove this once we've done more checks here.
|
2018-12-20 14:58:41 +11:00
|
|
|
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) {
|
2018-12-21 09:30:08 +11:00
|
|
|
// TODO: const this? Requires const if
|
2018-12-20 14:58:41 +11:00
|
|
|
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)
|
|
|
|
};
|
2018-12-21 10:15:23 +11:00
|
|
|
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),
|
2018-12-20 14:58:41 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-21 09:30:08 +11:00
|
|
|
/*
|
2018-12-20 14:58:41 +11:00
|
|
|
#[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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-21 09:30:08 +11:00
|
|
|
*/
|