gba/examples/hello_world.rs
Alissa Rao 2aa59bb341
Implement a sync API for working with global mutable state. (#107)
* Add IntelliJ workspace files to the .gitignore.

* Add a simple make_example script for Linux.

* Create a `sync` module with many GBA-specific sync utilties.

* Fix overflow error in debug mode in the hello_world crate.

* Fixes to DMA.

* Code cleanup for the sync module.

* Run rustfmt on new sync code.

* Fix up some names and documentation in the sync module.

* Add a few changes suggested by thomcc for the locks.

* Added needed compiler fences to `InitOnce::try_get`.
* Change the error in `RawMutex::raw_unlock` to better reflect the cause.

* Add a proper issue link to the __sync_synchronize hack.

* Disable interrupts during `InitOnce::try_get`.

* Fix some bad wording in the comments for `InitOnce::try_get`

* Use the new target in `cfg` checks to see if we're on GBA.

* Change registers used for transfer_align4_arm for the different target.

* Cleanup on sync_api changes for the target change.
2021-02-21 16:57:26 -07:00

85 lines
2.3 KiB
Rust

#![no_std]
#![feature(start)]
#![forbid(unsafe_code)]
use gba::{
fatal,
io::{
display::{DisplayControlSetting, DisplayMode, DISPCNT, VBLANK_SCANLINE, VCOUNT},
keypad::read_key_input,
},
vram::bitmap::Mode3,
Color,
};
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
// This kills the emulation with a message if we're running within mGBA.
fatal!("{}", info);
// If we're _not_ running within mGBA then we still need to not return, so
// loop forever doing nothing.
loop {}
}
/// Performs a busy loop until VBlank starts.
///
/// This is very inefficient, and please keep following the lessons until we
/// cover how interrupts work!
pub fn spin_until_vblank() {
while VCOUNT.read() < VBLANK_SCANLINE {}
}
/// Performs a busy loop until VDraw starts.
///
/// This is very inefficient, and please keep following the lessons until we
/// cover how interrupts work!
pub fn spin_until_vdraw() {
while VCOUNT.read() >= VBLANK_SCANLINE {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
const SETTING: DisplayControlSetting =
DisplayControlSetting::new().with_mode(DisplayMode::Mode3).with_bg2(true);
DISPCNT.write(SETTING);
let mut px = Mode3::WIDTH / 2;
let mut py = Mode3::HEIGHT / 2;
let mut color = Color::from_rgb(31, 0, 0);
loop {
// read our keys for this frame
let this_frame_keys = read_key_input();
// adjust game state and wait for vblank
px = px.wrapping_add((2 * this_frame_keys.x_tribool() as i32) as usize);
py = py.wrapping_add((2 * this_frame_keys.y_tribool() as i32) as usize);
if this_frame_keys.l() {
color = Color(color.0.rotate_left(5));
}
if this_frame_keys.r() {
color = Color(color.0.rotate_right(5));
}
// now we wait
spin_until_vblank();
// draw the new game and wait until the next frame starts.
if px >= Mode3::WIDTH || py >= Mode3::HEIGHT {
// out of bounds, reset the screen and position.
Mode3::dma_clear_to(Color::from_rgb(0, 0, 0));
px = Mode3::WIDTH / 2;
py = Mode3::HEIGHT / 2;
} else {
// draw the new part of the line
Mode3::write(px, py, color);
Mode3::write(px, py + 1, color);
Mode3::write(px + 1, py, color);
Mode3::write(px + 1, py + 1, color);
}
// now we wait again
spin_until_vdraw();
}
}