mrk-its / rust-mos

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
55 stars 7 forks source link

Making subroutine calls to specific addresses? #13

Closed ilyvion closed 1 year ago

ilyvion commented 1 year ago

Hey.

I wanted the compiler to output

LDA #$48
JSR $FFD2

so I had the idea to write my code as

let func = unsafe { core::mem::transmute::<*const (), fn(u8)>(0xFFD2_usize as _) };
func(0x48);

and it "works" except the JSR instruction just goes to somewhere seemingly random:

LDA #$48
JSR $026E

What's curious is that it seems to always become $026E regardless of what number I try to transmute, except for 0x0 which leads to entirely different codegen. (Presumably because it's considered an illegal address? Even though $0 is a perfectly legal memory location on the device I'm working with, but I digress.)

I'd resort to inline assembly, but Rust/LLVM only supports inline assembly for a few targets, mos not being one of them.

Any thoughts on what's going on or how to accomplish doing a correct JSR in Rust to a specific memory address?

ilyvion commented 1 year ago

And more specifically, how would one go about doing a JSR after having set the registers to specific values? Because a lot of the platforms for these chips have things like (this is for the CX16 screen_mode KERNAL subroutine):

Function Name: screen_mode Purpose: Get/Set the screen mode Call address: $FF5F Communication registers: .A, .X, .Y, .C Preparatory routines: None Error returns: .C = 1 in case of error Stack requirements: 4 Registers affected: .A, .X, .Y

Description: If .C is set, a call to this routine gets the current screen mode in .A, the width (in tiles) of the screen in .X, and the > height (in tiles) of the screen in .Y. If .C is clear, it sets the current screen mode to the value in .A. For a list of possible values, see the basic statement SCREEN. If the mode is unsupported, .C will be set, otherwise cleared.

and I can't think of how any way to do this in Rust right now, which pretty much stops me in my tracks...

mrk-its commented 1 year ago

I'd resort to inline assembly, but Rust/LLVM only supports inline assembly for a few targets, mos not being one of them.

Any thoughts on what's going on or how to accomplish doing a correct JSR in Rust to a specific memory address?

Inline assembly doesn't work yet, but you can define your helpers in external asm file. Take a look https://github.com/mrk-its/a800xl-utils/, files: src/cio.S, src/cio.rs, build.rs

llvm-mos calling convention doc may be also helpful: https://llvm-mos.org/wiki/C_calling_convention

ilyvion commented 1 year ago

Thanks, that helped a lot. 😄