mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 11:31:31 +11:00
make the BIOS test safe
This commit is contained in:
parent
ecc7ea940d
commit
08ff34ae43
103
src/bios.rs
103
src/bios.rs
|
@ -8,6 +8,8 @@
|
|||
//! whatever value is necessary for that function). Some functions also perform
|
||||
//! necessary checks to save you from yourself, such as not dividing by zero.
|
||||
|
||||
use super::register_bit;
|
||||
|
||||
//TODO: ALL functions in this module should have `if cfg!(test)` blocks. The
|
||||
//functions that never return must panic, the functions that return nothing
|
||||
//should just do so, and the math functions should just return the correct math
|
||||
|
@ -49,6 +51,9 @@
|
|||
/// perform UB, but such a scenario might exist.
|
||||
#[inline(always)]
|
||||
pub unsafe fn soft_reset() -> ! {
|
||||
if cfg!(test) {
|
||||
panic!("Attempted soft reset during testing");
|
||||
} else {
|
||||
asm!(/* ASM */ "swi 0x00"
|
||||
:/* OUT */ // none
|
||||
:/* INP */ // none
|
||||
|
@ -57,6 +62,7 @@ pub unsafe fn soft_reset() -> ! {
|
|||
);
|
||||
core::hint::unreachable_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x01`) RegisterRamReset.
|
||||
///
|
||||
|
@ -84,15 +90,34 @@ pub unsafe fn soft_reset() -> ! {
|
|||
/// memory, except in the case that you were executing out of EWRAM and clear
|
||||
/// that. If you do then you return to nothing and have a bad time.
|
||||
#[inline(always)]
|
||||
pub unsafe fn register_ram_reset(flags: u8) {
|
||||
pub unsafe fn register_ram_reset(flags: RegisterRAMResetFlags) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
asm!(/* ASM */ "swi 0x01"
|
||||
:/* OUT */ // none
|
||||
:/* INP */ "{r0}"(flags)
|
||||
:/* INP */ "{r0}"(flags.0)
|
||||
:/* CLO */ // none
|
||||
:/* OPT */ "volatile"
|
||||
);
|
||||
}
|
||||
//TODO(lokathor): newtype this flag business.
|
||||
}
|
||||
newtype! {
|
||||
/// Flags for use with `register_ram_reset`.
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||
RegisterRAMResetFlags, u8
|
||||
}
|
||||
#[allow(missing_docs)]
|
||||
impl RegisterRAMResetFlags {
|
||||
register_bit!(EWRAM, u8, 0, ewram);
|
||||
register_bit!(IWRAM, u8, 1 << 1, iwram);
|
||||
register_bit!(PALRAM, u8, 1 << 2, palram);
|
||||
register_bit!(VRAM, u8, 1 << 3, vram);
|
||||
register_bit!(OAM, u8, 1 << 4, oam);
|
||||
register_bit!(SIO, u8, 1 << 5, sio);
|
||||
register_bit!(SOUND, u8, 1 << 6, sound);
|
||||
register_bit!(OTHER_IO, u8, 1 << 7, other_io);
|
||||
}
|
||||
|
||||
/// (`swi 0x02`) Halts the CPU until an interrupt occurs.
|
||||
///
|
||||
|
@ -100,6 +125,9 @@ pub unsafe fn register_ram_reset(flags: u8) {
|
|||
/// any enabled interrupt triggers.
|
||||
#[inline(always)]
|
||||
pub fn halt() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x02"
|
||||
:/* OUT */ // none
|
||||
|
@ -109,6 +137,7 @@ pub fn halt() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x03`) Stops the CPU as well as most other components.
|
||||
///
|
||||
|
@ -120,6 +149,9 @@ pub fn halt() {
|
|||
/// optional externals such as rumble and infra-red.
|
||||
#[inline(always)]
|
||||
pub fn stop() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x03"
|
||||
:/* OUT */ // none
|
||||
|
@ -129,6 +161,7 @@ pub fn stop() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x04`) "IntrWait", similar to halt but with more options.
|
||||
///
|
||||
|
@ -145,6 +178,9 @@ pub fn stop() {
|
|||
/// acknowledgement.
|
||||
#[inline(always)]
|
||||
pub fn interrupt_wait(ignore_current_flags: bool, target_flags: u16) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x04"
|
||||
:/* OUT */ // none
|
||||
|
@ -154,6 +190,7 @@ pub fn interrupt_wait(ignore_current_flags: bool, target_flags: u16) {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO(lokathor): newtype this flag business.
|
||||
|
||||
/// (`swi 0x05`) "VBlankIntrWait", VBlank Interrupt Wait.
|
||||
|
@ -162,6 +199,9 @@ pub fn interrupt_wait(ignore_current_flags: bool, target_flags: u16) {
|
|||
/// must follow the same guidelines that `interrupt_wait` outlines.
|
||||
#[inline(always)]
|
||||
pub fn vblank_interrupt_wait() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x04"
|
||||
:/* OUT */ // none
|
||||
|
@ -171,6 +211,7 @@ pub fn vblank_interrupt_wait() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x06`) Software Division and Remainder.
|
||||
///
|
||||
|
@ -219,6 +260,9 @@ pub fn rem(numerator: i32, denominator: i32) -> i32 {
|
|||
/// by `2n` bits to get `n` more bits of fractional precision in your output.
|
||||
#[inline(always)]
|
||||
pub fn sqrt(val: u32) -> u16 {
|
||||
if cfg!(test) {
|
||||
0 // TODO: simulate this properly during testing builds.
|
||||
} else {
|
||||
let out: u16;
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x08"
|
||||
|
@ -230,6 +274,7 @@ pub fn sqrt(val: u32) -> u16 {
|
|||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x09`) Gives the arctangent of `theta`.
|
||||
///
|
||||
|
@ -239,6 +284,9 @@ pub fn sqrt(val: u32) -> u16 {
|
|||
/// Accuracy suffers if `theta` is less than `-pi/4` or greater than `pi/4`.
|
||||
#[inline(always)]
|
||||
pub fn atan(theta: i16) -> i16 {
|
||||
if cfg!(test) {
|
||||
0 // TODO: simulate this properly during testing builds.
|
||||
} else {
|
||||
let out: i16;
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x09"
|
||||
|
@ -250,6 +298,7 @@ pub fn atan(theta: i16) -> i16 {
|
|||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x0A`) Gives the atan2 of `y` over `x`.
|
||||
///
|
||||
|
@ -260,6 +309,9 @@ pub fn atan(theta: i16) -> i16 {
|
|||
/// integral, 14 bits for fractional.
|
||||
#[inline(always)]
|
||||
pub fn atan2(y: i16, x: i16) -> u16 {
|
||||
if cfg!(test) {
|
||||
0 // TODO: simulate this properly during testing builds.
|
||||
} else {
|
||||
let out: u16;
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x0A"
|
||||
|
@ -271,6 +323,7 @@ pub fn atan2(y: i16, x: i16) -> u16 {
|
|||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x0B`) "CpuSet", `u16` memory copy.
|
||||
///
|
||||
|
@ -283,6 +336,9 @@ pub fn atan2(y: i16, x: i16) -> u16 {
|
|||
/// * Both pointers must be aligned
|
||||
#[inline(always)]
|
||||
pub unsafe fn cpu_set16(src: *const u16, dest: *mut u16, count: u32, fixed_source: bool) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
let control = count + ((fixed_source as u32) << 24);
|
||||
asm!(/* ASM */ "swi 0x0B"
|
||||
:/* OUT */ // none
|
||||
|
@ -291,6 +347,7 @@ pub unsafe fn cpu_set16(src: *const u16, dest: *mut u16, count: u32, fixed_sourc
|
|||
:/* OPT */ "volatile"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x0B`) "CpuSet", `u32` memory copy/fill.
|
||||
///
|
||||
|
@ -303,6 +360,9 @@ pub unsafe fn cpu_set16(src: *const u16, dest: *mut u16, count: u32, fixed_sourc
|
|||
/// * Both pointers must be aligned
|
||||
#[inline(always)]
|
||||
pub unsafe fn cpu_set32(src: *const u32, dest: *mut u32, count: u32, fixed_source: bool) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
let control = count + ((fixed_source as u32) << 24) + (1 << 26);
|
||||
asm!(/* ASM */ "swi 0x0B"
|
||||
:/* OUT */ // none
|
||||
|
@ -311,6 +371,7 @@ pub unsafe fn cpu_set32(src: *const u32, dest: *mut u32, count: u32, fixed_sourc
|
|||
:/* OPT */ "volatile"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x0C`) "CpuFastSet", copies memory in 32 byte chunks.
|
||||
///
|
||||
|
@ -324,6 +385,9 @@ pub unsafe fn cpu_set32(src: *const u32, dest: *mut u32, count: u32, fixed_sourc
|
|||
/// * Both pointers must be aligned
|
||||
#[inline(always)]
|
||||
pub unsafe fn cpu_fast_set(src: *const u32, dest: *mut u32, count: u32, fixed_source: bool) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
let control = count + ((fixed_source as u32) << 24);
|
||||
asm!(/* ASM */ "swi 0x0C"
|
||||
:/* OUT */ // none
|
||||
|
@ -332,6 +396,7 @@ pub unsafe fn cpu_fast_set(src: *const u32, dest: *mut u32, count: u32, fixed_so
|
|||
:/* OPT */ "volatile"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x0C`) "GetBiosChecksum" (Undocumented)
|
||||
///
|
||||
|
@ -343,6 +408,9 @@ pub unsafe fn cpu_fast_set(src: *const u32, dest: *mut u32, count: u32, fixed_so
|
|||
/// some other value I guess you're probably running on an emulator that just
|
||||
/// broke the fourth wall.
|
||||
pub fn get_bios_checksum() -> u32 {
|
||||
if cfg!(test) {
|
||||
0
|
||||
} else {
|
||||
let out: u32;
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x0D"
|
||||
|
@ -354,6 +422,7 @@ pub fn get_bios_checksum() -> u32 {
|
|||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: these things will require that we build special structs
|
||||
|
||||
|
@ -376,6 +445,9 @@ pub fn get_bios_checksum() -> u32 {
|
|||
///
|
||||
/// The final sound level setting will be `level` * `0x200`.
|
||||
pub fn sound_bias(level: u32) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x19"
|
||||
:/* OUT */ // none
|
||||
|
@ -385,6 +457,7 @@ pub fn sound_bias(level: u32) {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//SoundDriverInit
|
||||
|
||||
|
@ -414,6 +487,9 @@ pub fn sound_bias(level: u32) {
|
|||
/// * 10: 40137
|
||||
/// * 11: 42048
|
||||
pub fn sound_driver_mode(mode: u32) {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x1B"
|
||||
:/* OUT */ // none
|
||||
|
@ -423,6 +499,7 @@ pub fn sound_driver_mode(mode: u32) {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO(lokathor): newtype this mode business.
|
||||
|
||||
/// (`swi 0x1C`) "SoundDriverMain", main of the sound driver
|
||||
|
@ -434,6 +511,9 @@ pub fn sound_driver_mode(mode: u32) {
|
|||
/// executed." --what?
|
||||
#[inline(always)]
|
||||
pub fn sound_driver_main() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x1C"
|
||||
:/* OUT */ // none
|
||||
|
@ -443,6 +523,7 @@ pub fn sound_driver_main() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x1D`) "SoundDriverVSync", resets the sound DMA.
|
||||
///
|
||||
|
@ -450,6 +531,9 @@ pub fn sound_driver_main() {
|
|||
/// vblank interrupt (every 1/60th of a second).
|
||||
#[inline(always)]
|
||||
pub fn sound_driver_vsync() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x1D"
|
||||
:/* OUT */ // none
|
||||
|
@ -459,6 +543,7 @@ pub fn sound_driver_vsync() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x1E`) "SoundChannelClear", clears the direct sound channels and stops
|
||||
/// the sound.
|
||||
|
@ -468,6 +553,9 @@ pub fn sound_driver_vsync() {
|
|||
/// --what?
|
||||
#[inline(always)]
|
||||
pub fn sound_channel_clear() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x1E"
|
||||
:/* OUT */ // none
|
||||
|
@ -477,6 +565,7 @@ pub fn sound_channel_clear() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MidiKey2Freq
|
||||
//MultiBoot
|
||||
|
@ -489,6 +578,9 @@ pub fn sound_channel_clear() {
|
|||
/// noise.
|
||||
#[inline(always)]
|
||||
pub fn sound_driver_vsync_off() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x28"
|
||||
:/* OUT */ // none
|
||||
|
@ -498,6 +590,7 @@ pub fn sound_driver_vsync_off() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (`swi 0x29`) "SoundDriverVSyncOn", enables sound that was stopped by
|
||||
/// `sound_driver_vsync_off`.
|
||||
|
@ -506,6 +599,9 @@ pub fn sound_driver_vsync_off() {
|
|||
/// interrupt followed by a `sound_driver_vsync` within 2/60th of a second.
|
||||
#[inline(always)]
|
||||
pub fn sound_driver_vsync_on() {
|
||||
if cfg!(test) {
|
||||
// do nothing in test mode
|
||||
} else {
|
||||
unsafe {
|
||||
asm!(/* ASM */ "swi 0x29"
|
||||
:/* OUT */ // none
|
||||
|
@ -515,3 +611,4 @@ pub fn sound_driver_vsync_on() {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue