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
|
.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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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 _)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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])?;
|
||||||
|
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 {
|
if high_score > 100 {
|
||||||
HIGHSCORE.borrow(cs).replace(0);
|
HIGHSCORE.write(0)
|
||||||
} else {
|
} else {
|
||||||
HIGHSCORE.borrow(cs).replace(high_score);
|
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));
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue