mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
partial intrinsic work
This commit is contained in:
parent
6cb50aa2eb
commit
8aa1bb0065
|
@ -14,6 +14,9 @@ publish = false
|
|||
[dependencies]
|
||||
gba-proc-macro = "0.2.1"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
panic = "abort"
|
||||
|
|
|
@ -34,6 +34,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
let key = ((this_frame_key_raw >> i) & 1) > 0;
|
||||
mode3_draw_pixel(15 - i, 0, if key { green } else { red });
|
||||
mode3_draw_pixel(15 - i, 1, if key { green } else { red });
|
||||
mode3_draw_pixel(50 - i, 10 / i, if key { green } else { red });
|
||||
}
|
||||
|
||||
wait_until_vdraw();
|
||||
|
|
71
src/intrinsics.rs
Normal file
71
src/intrinsics.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
//! Intrinsics that LLVM looks for when compiling.
|
||||
|
||||
/// Signed division
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub extern "aapcs" fn __aeabi_idiv(n: i32, d: i32) -> i32 {
|
||||
assert!(d != 0);
|
||||
let div_out: i32;
|
||||
let _mod_out: i32;
|
||||
unsafe {
|
||||
asm!(/* assembly template */ "swi 0x06"
|
||||
:/* output operands */ "={r0}"(div_out), "={r1}"(_mod_out)
|
||||
:/* input operands */ "{r0}"(n), "{r1}"(d)
|
||||
:/* clobbers */ "r3"
|
||||
:/* options */
|
||||
);
|
||||
}
|
||||
div_out
|
||||
}
|
||||
|
||||
/// Signed division alias for glibc reasons
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub extern "aapcs" fn __divsi3(n: i32, d: i32) -> i32 {
|
||||
// Note the different naming scheme.
|
||||
__aeabi_idiv(n, d)
|
||||
}
|
||||
|
||||
/// Unsigned division gets cast into signed values, divided, and cast back
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub extern "aapcs" fn __aeabi_uidiv(n: u32, d: u32) -> u32 {
|
||||
__aeabi_idiv(n as i32, d as i32) as u32
|
||||
}
|
||||
|
||||
/// Unsigned division alias for glibc reasons
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub extern "aapcs" fn __udivsi3(n: u32, d: u32) -> u32 {
|
||||
// Note the different naming scheme.
|
||||
__aeabi_uidiv(n, d)
|
||||
}
|
||||
|
||||
/// Count leading zeroes, required in debug mode for unknown reasons
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub extern "aapcs" fn __clzsi2(x: i32) -> i32 {
|
||||
let mut y = -(x >> 16); // If left half of x is 0,
|
||||
let mut m = (y >> 16) & 16; // set n = 16. If left half
|
||||
let mut n = 16 - m; // is nonzero, set n = 0 and
|
||||
let mut x = x >> m; // shift x right 16.
|
||||
// Now x is of the form 0000xxxx.
|
||||
y = x - 0x100; // If positions 8-15 are 0,
|
||||
m = (y >> 16) & 8; // add 8 to n and shift x left 8.
|
||||
n = n + m;
|
||||
x = x << m;
|
||||
|
||||
y = x - 0x1000; // If positions 12-15 are 0,
|
||||
m = (y >> 16) & 4; // add 4 to n and shift x left 4.
|
||||
n = n + m;
|
||||
x = x << m;
|
||||
|
||||
y = x - 0x4000; // If positions 14-15 are 0,
|
||||
m = (y >> 16) & 2; // add 2 to n and shift x left 2.
|
||||
n = n + m;
|
||||
x = x << m;
|
||||
|
||||
y = x >> 14; // Set y = 0, 1, 2, or 3.
|
||||
m = y & !(y >> 1); // Set m = 0, 1, 2, or 2 resp.
|
||||
n + 2 - m
|
||||
}
|
|
@ -116,6 +116,18 @@ pub fn vcount() -> u16 {
|
|||
unsafe { VCOUNT.read() }
|
||||
}
|
||||
|
||||
/// Performs a busy loop until VBlank starts.
|
||||
pub fn wait_until_vblank() {
|
||||
// TODO: make this the better version with BIOS and interrupts and such.
|
||||
while vcount() < SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
/// Performs a busy loop until VDraw starts.
|
||||
pub fn wait_until_vdraw() {
|
||||
// TODO: make this the better version with BIOS and interrupts and such.
|
||||
while vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
/// BG0 Control
|
||||
pub const BG0CNT: VolatilePtr<u16> = VolatilePtr(0x4000008 as *mut u16);
|
||||
|
||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -1,4 +1,5 @@
|
|||
#![cfg_attr(not(test), no_std)]
|
||||
#![feature(asm)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! This crate helps you write GBA ROMs.
|
||||
|
@ -26,11 +27,41 @@ pub mod core_extras;
|
|||
pub(crate) use crate::core_extras::*;
|
||||
|
||||
pub mod io_registers;
|
||||
pub(crate) use crate::io_registers::*;
|
||||
|
||||
pub mod video_ram;
|
||||
pub(crate) use crate::video_ram::*;
|
||||
|
||||
pub mod intrinsics;
|
||||
|
||||
/// 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
|
||||
}
|
||||
|
||||
/// BIOS Call: Div (GBA SWI 0x06).
|
||||
///
|
||||
/// Gives the DIV and MOD output of `numerator / denominator`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `denominator` is 0.
|
||||
#[inline]
|
||||
pub fn div_mod(numerator: i32, denominator: i32) -> (i32, i32) {
|
||||
// The BIOS includes several System Call Functions which can be accessed by
|
||||
// SWI instructions. Incoming parameters are usually passed through registers
|
||||
// R0,R1,R2,R3. Outgoing registers R0,R1,R3 are typically containing either
|
||||
// garbage, or return value(s). All other registers (R2,R4-R14) are kept
|
||||
// unchanged. --GBATEK
|
||||
assert!(denominator != 0);
|
||||
let div_out: i32;
|
||||
let mod_out: i32;
|
||||
unsafe {
|
||||
asm!(/* assembly template */ "swi 0x06"
|
||||
:/* output operands */ "={r0}"(div_out), "={r1}"(mod_out)
|
||||
:/* input operands */ "{r0}"(numerator), "{r1}"(denominator)
|
||||
:/* clobbers */ "r3"
|
||||
:/* options */
|
||||
);
|
||||
}
|
||||
(div_out, mod_out)
|
||||
}
|
||||
|
|
|
@ -28,18 +28,6 @@ pub const SCREEN_HEIGHT: isize = 160;
|
|||
/// value as just being a `usize`.
|
||||
pub const VRAM_BASE_ADDRESS: usize = 0x0600_0000;
|
||||
|
||||
/// Performs a busy loop until VBlank starts.
|
||||
pub fn wait_until_vblank() {
|
||||
// TODO: make this the better version with BIOS and interrupts and such.
|
||||
while vcount() < SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
/// Performs a busy loop until VDraw starts.
|
||||
pub fn wait_until_vdraw() {
|
||||
// TODO: make this the better version with BIOS and interrupts and such.
|
||||
while vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
/// Draws a pixel to the screen while in Display Mode 3, with bounds checks.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
Loading…
Reference in a new issue