mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
Improve codestyle in asm_routines.s, remove unsafe save implementation in hyperspace-roll.
This commit is contained in:
parent
ec41db2fc9
commit
2be44c12e5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 _)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue