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
.endfunc
.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);
@
@ A routine that reads a byte from a given memory offset.
@
.thumb
.global WramReadByte
.thumb_func
.align 2
WramReadByte:
ldr r1, =WramReadByteInner
bx r1
.section .data
.thumb
.thumb_func
.align 2
WramReadByteInner:
agb_thumb_func agb_rs__WramReadByte
ldrb r0, [r0]
mov pc, lr
.section .text
agb_thumb_end agb_rs__WramReadByte
@
@ bool WramVerifyBuf(const char* buf1, const char* buf2, int count);
@
@ A routine that compares two memory offsets.
@
.thumb
.global WramVerifyBuf
.thumb_func
.align 2
WramVerifyBuf:
agb_thumb_func agb_rs__WramVerifyBuf
push {r4-r5, lr}
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
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
ldrb r3, [r5,r2]
1: ldrb r3, [r5,r2]
ldrb r4, [r1,r2]
cmp r3, r4
bne 0f
sub r2, #1
bpl WramVerifyBufInner
bpl 1b
@ Returns from the function successfully
movs r0, #1
0: @ Jumps to here return the function unsuccessfully, because r0 contains 0 at this point
pop {r4-r5, pc}
agb_thumb_end agb_rs__WramVerifyBuf
.section .text
@
@ void WramXferBuf(const char* source, char* dest, int count);
@
@ A routine that copies one buffer into another.
@
.thumb
.global WramXferBuf
.thumb_func
.align 2
WramXferBuf:
ldr r3, =WramXferBufInner
bx r3
.pool
.section .data
.thumb
.thumb_func
.align 2
WramXferBufInner:
sub r2, #1
agb_thumb_func agb_rs__WramXferBuf
0: sub r2, #1
ldrb r3, [r0,r2]
strb r3, [r1,r2]
bne WramXferBufInner
bne 0b
mov pc, lr
.pool
.section .text
agb_thumb_end agb_rs__WramXferBuf

View file

@ -3,9 +3,9 @@
//! performed via code in WRAM and cannot be accessed by DMA.
extern "C" {
fn WramXferBuf(src: *const u8, dst: *mut u8, count: usize);
fn WramReadByte(src: *const u8) -> u8;
fn WramVerifyBuf(buf1: *const u8, buf2: *const u8, count: usize) -> bool;
fn agb_rs__WramXferBuf(src: *const u8, dst: *mut u8, count: usize);
fn agb_rs__WramReadByte(src: *const u8) -> u8;
fn agb_rs__WramVerifyBuf(buf1: *const u8, buf2: *const u8, count: usize) -> bool;
}
/// Copies data from a given memory address into a buffer.
@ -18,7 +18,7 @@ extern "C" {
#[inline(always)]
pub unsafe fn read_raw_buf(dst: &mut [u8], src: usize) {
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)]
pub unsafe fn write_raw_buf(dst: usize, src: &[u8]) {
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)]
pub unsafe fn verify_raw_buf(buf1: &[u8], buf2: usize) -> bool {
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 {
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.
#[inline(always)]
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.
///
/// 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();
set_save_implementation(&sram::BatteryBackedAccess);
}
@ -379,14 +379,15 @@ impl SaveManager {
///
/// You must have initialized the save manager beforehand to use a specific
/// type of media before calling this method.
pub fn access() -> Result<SaveData, Error> {
pub fn access(&mut self) -> Result<SaveData, Error> {
SaveData::new(None)
}
/// 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
/// 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))
}
}

View file

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

View file

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