Skip to content

Inconsistent behavior writing OAM with different optimization levels #213

@undecidedapollo

Description

@undecidedapollo

When modifying OAM for objects I utilize the OBJ_ATTR_ALL.index(x).write() functions to update specific objects, like so:

OBJ_ATTR_ALL.index(0).write(ObjAttr::new());

I recently noticed weird behavior where my objects would update as expected in dev mode (and lower levels of optimizations (2, 3)) but would stop updating in optimization modes "s" and "z". After digging into the assembly (of which I know little about), I noticed that it would replace the three strh (Store Half Word) instructions with a __aeabi_memcpy. When the memcpy implementation was present the updates would no longer reflect, I assume because OAM requires half-word writes and memcpy does 8 bit writes.

I was able to get around this by adding a new function onto ObjAttr in the GBA crate as a workaround and inverting the calling convention. This uses explicit write_volatile calls for each u16 in the ObjAttr struct to ensure each is written as is and not optimized away. Using a single write_volatile for the struct results in the same memcpy optimization:

pub struct ObjAttr(pub ObjAttr0, pub ObjAttr1, pub ObjAttr2);

impl ObjAttr {
  // Existing logic
  #[inline]
  pub fn write(&self, addr: VolAddress<ObjAttr, Safe, 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);
    }
  }
}

Example usage:

ObjAttr::new().write(OBJ_ATTR_ALL.index(0));

I've uploaded a simplified repo with an example, compiling with lower optimization levels results in strh instructions where compiling at higher optimizations results in memcpy.

https://github.com/undecidedapollo/gba-objattr-volatile-write-bug

I'm new to GBA development as a whole, am a relative beginner with rust, and know little about assembly, so I may have some details backwards / making a simple mistake. Thanks for looking into this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugsomething is causing a problem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions