Improve codestyle in asm_routines.s, remove unsafe save implementation in hyperspace-roll.

This commit is contained in:
Alissa Rao 2022-08-17 01:04:07 -07:00
parent ec41db2fc9
commit 2be44c12e5
No known key found for this signature in database
GPG key ID: 9314D8F6745E881E
6 changed files with 70 additions and 94 deletions

View file

@ -13,3 +13,19 @@
.size \functionName,.-\functionName .size \functionName,.-\functionName
.endfunc .endfunc
.endm .endm
.macro agb_thumb_func functionName:req
.section .iwram.\functionName, "ax", %progbits
.thumb
.align 2
.global \functionName
.type \functionName, %function
.func \functionName
\functionName:
.endm
.macro agb_thumb_end functionName:req
.pool
.size \functionName,.-\functionName
.endfunc
.endm

View file

@ -1,89 +1,49 @@
.include "src/asm_include.s"
@ @
@ char WramReadByte(const char* offset); @ char WramReadByte(const char* offset);
@ @
@ A routine that reads a byte from a given memory offset. @ A routine that reads a byte from a given memory offset.
@ @
.thumb agb_thumb_func agb_rs__WramReadByte
.global WramReadByte
.thumb_func
.align 2
WramReadByte:
ldr r1, =WramReadByteInner
bx r1
.section .data
.thumb
.thumb_func
.align 2
WramReadByteInner:
ldrb r0, [r0] ldrb r0, [r0]
mov pc, lr mov pc, lr
agb_thumb_end agb_rs__WramReadByte
.section .text
@ @
@ bool WramVerifyBuf(const char* buf1, const char* buf2, int count); @ bool WramVerifyBuf(const char* buf1, const char* buf2, int count);
@ @
@ A routine that compares two memory offsets. @ A routine that compares two memory offsets.
@ @
.thumb agb_thumb_func agb_rs__WramVerifyBuf
.global WramVerifyBuf
.thumb_func
.align 2
WramVerifyBuf:
push {r4-r5, lr} push {r4-r5, lr}
movs r5, r0 @ set up r5 to be r0, so we can use it immediately for the return result movs r5, r0 @ set up r5 to be r0, so we can use it immediately for the return result
movs r0, #0 @ set up r0 so the default return result is false movs r0, #0 @ set up r0 so the default return result is false
ldr r4, =WramVerifyBufInner
bx r4 @ jump to the part in WRAM
.section .data
.thumb
.thumb_func
.align 2
WramVerifyBufInner:
@ At this point, buf1 is actually in r5, so r0 can be used as a status return @ At this point, buf1 is actually in r5, so r0 can be used as a status return
ldrb r3, [r5,r2] 1: ldrb r3, [r5,r2]
ldrb r4, [r1,r2] ldrb r4, [r1,r2]
cmp r3, r4 cmp r3, r4
bne 0f bne 0f
sub r2, #1 sub r2, #1
bpl WramVerifyBufInner bpl 1b
@ Returns from the function successfully @ Returns from the function successfully
movs r0, #1 movs r0, #1
0: @ Jumps to here return the function unsuccessfully, because r0 contains 0 at this point 0: @ Jumps to here return the function unsuccessfully, because r0 contains 0 at this point
pop {r4-r5, pc} pop {r4-r5, pc}
agb_thumb_end agb_rs__WramVerifyBuf
.section .text
@ @
@ void WramXferBuf(const char* source, char* dest, int count); @ void WramXferBuf(const char* source, char* dest, int count);
@ @
@ A routine that copies one buffer into another. @ A routine that copies one buffer into another.
@ @
.thumb agb_thumb_func agb_rs__WramXferBuf
.global WramXferBuf 0: sub r2, #1
.thumb_func
.align 2
WramXferBuf:
ldr r3, =WramXferBufInner
bx r3
.pool
.section .data
.thumb
.thumb_func
.align 2
WramXferBufInner:
sub r2, #1
ldrb r3, [r0,r2] ldrb r3, [r0,r2]
strb r3, [r1,r2] strb r3, [r1,r2]
bne WramXferBufInner bne 0b
mov pc, lr mov pc, lr
agb_thumb_end agb_rs__WramXferBuf
.pool
.section .text

View file

@ -3,9 +3,9 @@
//! performed via code in WRAM and cannot be accessed by DMA. //! performed via code in WRAM and cannot be accessed by DMA.
extern "C" { extern "C" {
fn WramXferBuf(src: *const u8, dst: *mut u8, count: usize); fn agb_rs__WramXferBuf(src: *const u8, dst: *mut u8, count: usize);
fn WramReadByte(src: *const u8) -> u8; fn agb_rs__WramReadByte(src: *const u8) -> u8;
fn WramVerifyBuf(buf1: *const u8, buf2: *const u8, count: usize) -> bool; fn agb_rs__WramVerifyBuf(buf1: *const u8, buf2: *const u8, count: usize) -> bool;
} }
/// Copies data from a given memory address into a buffer. /// Copies data from a given memory address into a buffer.
@ -18,7 +18,7 @@ extern "C" {
#[inline(always)] #[inline(always)]
pub unsafe fn read_raw_buf(dst: &mut [u8], src: usize) { pub unsafe fn read_raw_buf(dst: &mut [u8], src: usize) {
if dst.len() != 0 { if dst.len() != 0 {
WramXferBuf(src as _, dst.as_mut_ptr(), dst.len()); agb_rs__WramXferBuf(src as _, dst.as_mut_ptr(), dst.len());
} }
} }
@ -31,7 +31,7 @@ pub unsafe fn read_raw_buf(dst: &mut [u8], src: usize) {
#[inline(always)] #[inline(always)]
pub unsafe fn write_raw_buf(dst: usize, src: &[u8]) { pub unsafe fn write_raw_buf(dst: usize, src: &[u8]) {
if src.len() != 0 { if src.len() != 0 {
WramXferBuf(src.as_ptr(), dst as _, src.len()); agb_rs__WramXferBuf(src.as_ptr(), dst as _, src.len());
} }
} }
@ -45,7 +45,7 @@ pub unsafe fn write_raw_buf(dst: usize, src: &[u8]) {
#[inline(always)] #[inline(always)]
pub unsafe fn verify_raw_buf(buf1: &[u8], buf2: usize) -> bool { pub unsafe fn verify_raw_buf(buf1: &[u8], buf2: usize) -> bool {
if buf1.len() != 0 { if buf1.len() != 0 {
WramVerifyBuf(buf1.as_ptr(), buf2 as _, buf1.len() - 1) agb_rs__WramVerifyBuf(buf1.as_ptr(), buf2 as _, buf1.len() - 1)
} else { } else {
true true
} }
@ -59,5 +59,5 @@ pub unsafe fn verify_raw_buf(buf1: &[u8], buf2: usize) -> bool {
/// This uses raw addresses into the memory space. Use with care. /// This uses raw addresses into the memory space. Use with care.
#[inline(always)] #[inline(always)]
pub unsafe fn read_raw_byte(src: usize) -> u8 { pub unsafe fn read_raw_byte(src: usize) -> u8 {
WramReadByte(src as _) agb_rs__WramReadByte(src as _)
} }

View file

@ -370,7 +370,7 @@ impl SaveManager {
/// given save type. /// given save type.
/// ///
/// Only one `init_*` function may be called in the lifetime of the program. /// Only one `init_*` function may be called in the lifetime of the program.
pub fn init_sram() { pub fn init_sram(&mut self) {
marker::emit_sram_marker(); marker::emit_sram_marker();
set_save_implementation(&sram::BatteryBackedAccess); set_save_implementation(&sram::BatteryBackedAccess);
} }
@ -379,14 +379,15 @@ impl SaveManager {
/// ///
/// You must have initialized the save manager beforehand to use a specific /// You must have initialized the save manager beforehand to use a specific
/// type of media before calling this method. /// type of media before calling this method.
pub fn access() -> Result<SaveData, Error> { pub fn access(&mut self) -> Result<SaveData, Error> {
SaveData::new(None) SaveData::new(None)
} }
/// Creates a new accessor to the save data that uses the given timer for timeouts. /// Creates a new accessor to the save data that uses the given timer for timeouts.
/// ///
/// You must have initialized the save manager beforehand to use a specific /// You must have initialized the save manager beforehand to use a specific
/// type of media before calling this method. /// type of media before calling this method.
pub fn access_with_timer(timer: Timer) -> Result<SaveData, Error> { pub fn access_with_timer(&mut self, timer: Timer) -> Result<SaveData, Error> {
SaveData::new(Some(timer)) SaveData::new(Some(timer))
} }
} }

View file

@ -96,10 +96,10 @@ struct Agb<'a> {
} }
fn main(mut gba: agb::Gba) -> ! { fn main(mut gba: agb::Gba) -> ! {
save::init_save(); save::init_save(&mut gba).expect("Could not initialize save game");
if save::load_high_score() > 1000 { if save::load_high_score() > 1000 {
save::save_high_score(0); save::save_high_score(&mut gba, 0).expect("Could not reset high score");
} }
let gfx = gba.display.object.get(); let gfx = gba.display.object.get();
@ -207,7 +207,8 @@ fn main(mut gba: agb::Gba) -> ! {
agb.obj.commit(); agb.obj.commit();
agb.sfx.customise(); agb.sfx.customise();
if save::load_high_score() < current_level { if save::load_high_score() < current_level {
save::save_high_score(current_level); save::save_high_score(&mut gba, current_level)
.expect("Could not save high score");
} }
break; break;
} }

View file

@ -1,44 +1,42 @@
use agb::interrupt::free; use agb::Gba;
use bare_metal::Mutex; use agb::save::Error;
use core::cell::RefCell; use agb::sync::Static;
const RAM_ADDRESS: *mut u8 = 0x0E00_0000 as *mut u8; static HIGHSCORE: Static<u32> = Static::new(0);
const HIGH_SCORE_ADDRESS_START: *mut u8 = RAM_ADDRESS.wrapping_offset(1);
static HIGHSCORE: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0)); pub fn init_save(gba: &mut Gba) -> Result<(), Error> {
gba.save.init_sram();
pub fn init_save() { let mut access = gba.save.access()?;
if (unsafe { RAM_ADDRESS.read_volatile() } == !0) {
save_high_score(0);
unsafe { RAM_ADDRESS.write_volatile(0) };
}
let mut a = [0; 4]; let mut buffer = [0; 1];
for (idx, a) in a.iter_mut().enumerate() { access.read(0, &mut buffer)?;
*a = unsafe { HIGH_SCORE_ADDRESS_START.add(idx).read_volatile() };
}
let high_score = u32::from_le_bytes(a); if buffer[0] != 0 {
access.prepare_write(0..1)?.write(0, &[0])?;
free(|cs| { core::mem::drop(access);
if high_score > 100 { save_high_score(gba, 0)?;
HIGHSCORE.borrow(cs).replace(0);
} else { } else {
HIGHSCORE.borrow(cs).replace(high_score); let mut buffer = [0; 4];
access.read(1, &mut buffer)?;
let high_score = u32::from_le_bytes(buffer);
if high_score > 100 {
HIGHSCORE.write(0)
} else {
HIGHSCORE.write(high_score)
} }
}); }
Ok(())
} }
pub fn load_high_score() -> u32 { pub fn load_high_score() -> u32 {
free(|cs| *HIGHSCORE.borrow(cs).borrow()) HIGHSCORE.read()
} }
pub fn save_high_score(score: u32) { pub fn save_high_score(gba: &mut Gba, score: u32) -> Result<(), Error> {
let a = score.to_le_bytes(); gba.save.access()?.prepare_write(1..5)?.write(1, &score.to_le_bytes())?;
HIGHSCORE.write(score);
for (idx, &a) in a.iter().enumerate() { Ok(())
unsafe { HIGH_SCORE_ADDRESS_START.add(idx).write_volatile(a) };
}
free(|cs| HIGHSCORE.borrow(cs).replace(score));
} }