Skip to content

Commit c7604cb

Browse files
OBJ_ATTR_ALL / VolSeries<ObjAttr> read-only.
ObjAttr write function. Extension trait for VolAddress<ObjAttr>.
1 parent 6a3fcc1 commit c7604cb

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

src/mmio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def_mmio!(0x0700_0000 = OBJ_ATTR0: VolSeries<ObjAttr0, Safe, Safe, 128, {size_of
264264
def_mmio!(0x0700_0002 = OBJ_ATTR1: VolSeries<ObjAttr1, Safe, Safe, 128, {size_of::<[u16;4]>()}>; "Object attributes 1.");
265265
def_mmio!(0x0700_0004 = OBJ_ATTR2: VolSeries<ObjAttr2, Safe, Safe, 128, {size_of::<[u16;4]>()}>; "Object attributes 2.");
266266

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

269269
def_mmio!(0x0700_0006 = AFFINE_PARAM_A: VolSeries<i16fx8, Safe, Safe, 32, {size_of::<[u16;16]>()}>; "Affine parameters A.");
270270
def_mmio!(0x0700_000E = AFFINE_PARAM_B: VolSeries<i16fx8, Safe, Safe, 32, {size_of::<[u16;16]>()}>; "Affine parameters B.");

src/video/obj.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,26 @@
1919
//! has one field for each 16-bit group of attributes: [ObjAttr0], [ObjAttr1],
2020
//! [ObjAttr2].
2121
//!
22-
//! When you've got an object's data configured how you want, use either the
23-
//! [`OBJ_ATTR_ALL`] control (to write all fields at once) or the [`OBJ_ATTR0`],
24-
//! [`OBJ_ATTR1`], and/or [`OBJ_ATTR2`] controls (to write just some of the
25-
//! fields).
22+
//! When you've got an object's data configured how you want, use the `write`
23+
//! function on the [ObjAttr] struct, the [ObjAttrWriteExt] extension trait for
24+
//! the [`OBJ_ATTR_ALL`] control (to write all fields at once), or the
25+
//! [`OBJ_ATTR0`], [`OBJ_ATTR1`], and/or [`OBJ_ATTR2`] controls (to write just
26+
//! some of the fields).
2627
//!
2728
//! **Note:** When the GBA first boots, the object layer will be off but the
2829
//! object entries in OAM will *not* be set to prevent individual objects from
2930
//! being displayed. Before enabling the object layer you should generally set
3031
//! the [ObjDisplayStyle] of all [ObjAttr0] fields so that any objects you're
3132
//! not using don't appear on the screen. Otherwise, you'll end up with
3233
//! un-configured objects appearing in the upper left corner of the display.
34+
//!
35+
//! [`OBJ_ATTR_ALL`] is defined as read-only because writing to OAM requires
36+
//! halfword alignment, and at higher compiler optimization levels the compiler
37+
//! will generate a `memcpy` call which may do byte-wise writes. To avoid this,
38+
//! use the `write` function on the [ObjAttr] struct, the `write` function on
39+
//! the [ObjAttrWriteExt] trait implemented for the [`OBJ_ATTR_ALL`] control,
40+
//! or write to the individual [`OBJ_ATTR0`], [`OBJ_ATTR1`], and [`OBJ_ATTR2`]
41+
//! controls.
3342
3443
use super::*;
3544

@@ -157,4 +166,24 @@ impl ObjAttr {
157166
pub fn set_palbank(&mut self, palbank: u16) {
158167
self.2 = self.2.with_palbank(palbank);
159168
}
169+
#[inline]
170+
pub fn write(&self, addr: VolAddress<ObjAttr, Safe, ()>) {
171+
unsafe {
172+
let addr: *mut u16 = addr.as_usize() as *mut u16;
173+
core::ptr::write_volatile(addr.add(0), self.0 .0);
174+
core::ptr::write_volatile(addr.add(1), self.1 .0);
175+
core::ptr::write_volatile(addr.add(2), self.2 .0);
176+
}
177+
}
178+
}
179+
180+
pub trait ObjAttrWriteExt {
181+
fn write(&self, attr: ObjAttr);
182+
}
183+
184+
impl ObjAttrWriteExt for VolAddress<ObjAttr, Safe, ()> {
185+
#[inline]
186+
fn write(&self, attr: ObjAttr) {
187+
attr.write(*self);
188+
}
160189
}

0 commit comments

Comments
 (0)