Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def_mmio!(0x0700_0000 = OBJ_ATTR0: VolSeries<ObjAttr0, Safe, Safe, 128, {size_of
def_mmio!(0x0700_0002 = OBJ_ATTR1: VolSeries<ObjAttr1, Safe, Safe, 128, {size_of::<[u16;4]>()}>; "Object attributes 1.");
def_mmio!(0x0700_0004 = OBJ_ATTR2: VolSeries<ObjAttr2, Safe, Safe, 128, {size_of::<[u16;4]>()}>; "Object attributes 2.");

def_mmio!(0x0700_0000 = OBJ_ATTR_ALL: VolSeries<ObjAttr, Safe, Safe, 128, {size_of::<[u16;4]>()}>; "Object attributes (all in one).");
def_mmio!(0x0700_0000 = OBJ_ATTR_ALL: VolSeries<ObjAttr, Safe, (), 128, {size_of::<[u16;4]>()}>; "Object attributes (all in one), read-only.");

def_mmio!(0x0700_0006 = AFFINE_PARAM_A: VolSeries<i16fx8, Safe, Safe, 32, {size_of::<[u16;16]>()}>; "Affine parameters A.");
def_mmio!(0x0700_000E = AFFINE_PARAM_B: VolSeries<i16fx8, Safe, Safe, 32, {size_of::<[u16;16]>()}>; "Affine parameters B.");
Expand Down
38 changes: 34 additions & 4 deletions src/video/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,29 @@
//! has one field for each 16-bit group of attributes: [ObjAttr0], [ObjAttr1],
//! [ObjAttr2].
//!
//! When you've got an object's data configured how you want, use either the
//! [`OBJ_ATTR_ALL`] control (to write all fields at once) or the [`OBJ_ATTR0`],
//! [`OBJ_ATTR1`], and/or [`OBJ_ATTR2`] controls (to write just some of the
//! fields).
//! When you've got an object's data configured how you want, use the `write`
//! function on the [ObjAttr] struct, the [ObjAttrWriteExt] extension trait for
//! the [`OBJ_ATTR_ALL`] control (to write all fields at once), or the
//! [`OBJ_ATTR0`], [`OBJ_ATTR1`], and/or [`OBJ_ATTR2`] controls (to write just
//! some of the fields).
//!
//! **Note:** When the GBA first boots, the object layer will be off but the
//! object entries in OAM will *not* be set to prevent individual objects from
//! being displayed. Before enabling the object layer you should generally set
//! the [ObjDisplayStyle] of all [ObjAttr0] fields so that any objects you're
//! not using don't appear on the screen. Otherwise, you'll end up with
//! un-configured objects appearing in the upper left corner of the display.
//!
//! [`OBJ_ATTR_ALL`] is defined as read-only because writing to OAM requires
//! halfword alignment, and at higher compiler optimization levels the compiler
//! will generate a `memcpy` call which may do byte-wise writes. To avoid this,
//! use the `write` function on the [ObjAttr] struct, the `write` function on
//! the [ObjAttrWriteExt] trait implemented for the [`OBJ_ATTR_ALL`] control,
//! or write to the individual [`OBJ_ATTR0`], [`OBJ_ATTR1`], and [`OBJ_ATTR2`]
//! controls.

use super::*;
use voladdress::{Safe, VolAddress};

/// How the object should be displayed.
///
Expand Down Expand Up @@ -157,4 +167,24 @@ impl ObjAttr {
pub fn set_palbank(&mut self, palbank: u16) {
self.2 = self.2.with_palbank(palbank);
}
#[inline]
pub fn write(&self, addr: VolAddress<ObjAttr, Safe, ()>) {
unsafe {
let addr: *mut u16 = addr.as_usize() as *mut u16;
core::ptr::write_volatile(addr.add(0), self.0 .0);
core::ptr::write_volatile(addr.add(1), self.1 .0);
core::ptr::write_volatile(addr.add(2), self.2 .0);
}
}
}

pub trait ObjAttrWriteExt {
fn write(&self, attr: ObjAttr);
}

impl ObjAttrWriteExt for VolAddress<ObjAttr, Safe, ()> {
#[inline]
fn write(&self, attr: ObjAttr) {
attr.write(*self);
}
}
Loading