diff --git a/Cargo.toml b/Cargo.toml index c1cf2b7..67f21a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xtensa-lx" -version = "0.3.0" +version = "0.4.0" description = "Low level access for xtensa lx processors and peripherals" categories = ["embedded", "hardware-support", "no-std"] keywords = ["xtensa", "lx", "register", "peripheral"] diff --git a/src/lib.rs b/src/lib.rs index abc1df5..708d3ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,11 +30,18 @@ pub fn get_stack_pointer() -> *const u32 { /// `stack` pointer to the non-inclusive end of the stack (must be 16-byte aligned) #[inline(always)] pub unsafe fn set_stack_pointer(stack: *mut u32) { - asm!(" - movi a0, 0 - mov sp, {0} - ", - in(reg) stack, out("a0") _, options(nostack) + // FIXME: this function relies on it getting inlined - if it doesn't inline it will try and return from this function using the adress in `a0` which has just been trashed... + // According to https://nnethercote.github.io/perf-book/inlining.html: + // "Inline attributes do not guarantee that a function is inlined or not inlined, but in practice, #[inline(always)] will cause inlining in all but the most exceptional cases." + // Is this good enough? Should we rewrite these as a macro to guarentee inlining? + + + // NOTE: modification of the `sp` & `a0` is not typically allowed inside inline asm!, + // but because we *need* to modify it we can do so by ommiting it from the clobber + asm!( + "movi a0, 0", // trash return register + "mov sp, {0}", // move stack pointer + in(reg) stack, options(nostack) ); } @@ -42,16 +49,15 @@ pub unsafe fn set_stack_pointer(stack: *mut u32) { #[inline(always)] pub fn get_program_counter() -> *const u32 { let x: *const u32; - let _y: u32; unsafe { asm!(" - mov {1}, a0 + mov {1}, {2} call0 1f .align 4 1: - mov {0}, a0 - mov a0, {1} - ", out(reg) x, out(reg) _y, out("a0") _, options(nostack)) + mov {0}, {2} + mov {2}, {1} + ", out(reg) x, out(reg) _, out(reg) _, options(nostack)) }; x }