1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Nintendo DS system & game bootstrapping related functions.

use crate::ffi;

/// Probably related to booting the game?
///
/// This function prints the debug message "task proc boot".
///
/// # Safety
/// This function is related to game-boot and will probably modify a lot of global data.
pub unsafe fn task_proc_boot() {
    ffi::TaskProcBoot();
}

/// Presumably blocks until the program receives an interrupt.
///
/// This just calls (in Ghidra terminology) coproc_moveto_Wait_for_interrupt(0).
/// See <https://en.wikipedia.org/wiki/ARM_architecture_family#Coprocessors>.
pub fn wait_for_interrupt() {
    unsafe {
        ffi::WaitForInterrupt();
    }
}

/// Sets the Interrupt Master Enable (IME) register to 1, which enables all CPU interrupts
/// (if enabled in the Interrupt Enable (IE) register).
///
/// See <https://problemkaputt.de/gbatek.htm#dsiomaps>.
///
/// Returns the old value in the IME register.
///
/// # Safety
/// The caller needs to make sure the system is in a state where it is safe to enable interrupts.
pub unsafe fn enable_all_interrupts() -> bool {
    ffi::EnableAllInterrupts() > 0
}

/// Sets the Interrupt Master Enable (IME) register to 0, which disables all CPU interrupts
/// (even if enabled in the Interrupt Enable (IE) register).
///
/// See <https://problemkaputt.de/gbatek.htm#dsiomaps>.
///
/// Returns the old value in the IME register.
///
/// # Safety
/// The caller needs to make sure the system is in a state where it is safe to disable interrupts.
pub unsafe fn disable_all_interrupts() -> bool {
    ffi::DisableAllInterrupts() > 0
}

/// Get the current (system?) time as an IEEE 754 floating-point number.
///
/// Returns the current time (in seconds?).
pub fn get_time() -> f32 {
    unsafe { ffi::GetTime() }
}

/// Probably resumes the sound player if paused?
///
/// # Safety
/// This function manipulates low-level global state.
pub unsafe fn sound_resume() -> bool {
    ffi::SoundResume() > 0
}

/// Probably aborts the program with some status code? It seems to serve a similar purpose to the
/// exit(3) function.
///
/// This function prints the debug string "card pull out %d" with the status code.
///
/// # Safety
/// This function manipulates low-level global state.
pub unsafe fn card_pull_out_with_status(status: i32) {
    ffi::CardPullOutWithStatus(status);
}

/// Sets some global flag that probably triggers system exit?
///
/// This function prints the debug string "card pull out".
///
/// # Safety
/// This function manipulates low-level global state.
pub unsafe fn card_pull_out() {
    ffi::CardPullOut();
}

/// Sets some global flag that maybe indicates a save error?
///
/// This function prints the debug string "card backup error".
///
/// # Safety
/// This function manipulates low-level global state.
pub unsafe fn card_backup_error() {
    ffi::CardBackupError();
}

/// Maybe halts the process display?
///
/// This function prints the debug string "halt process disp %d" with the status code.
///
/// # Safety
/// This function manipulates low-level global state.
pub unsafe fn halt_process_disp(status_code: i32) {
    ffi::HaltProcessDisp(status_code);
}

/// Supposed to return a debug flag. Just returns 0 in the final binary.
pub fn get_debug_flag1(flag_id: u32) -> u32 {
    // SAFETY: This is more or less an "atomic" operation.
    unsafe { ffi::GetDebugFlag1(flag_id) }
}

/// Supposed to return a debug flag. Just returns 0 in the final binary.
pub fn get_debug_flag2(flag_id: u32) -> u32 {
    // SAFETY: This is more or less an "atomic" operation.
    unsafe { ffi::GetDebugFlag2(flag_id) }
}

/// Supposed to set a debug flag. No-op in the final binary.
pub fn set_debug_flag1(flag_id: u32, value: u32) {
    // SAFETY: This is more or less an "atomic" operation.
    unsafe { ffi::SetDebugFlag1(flag_id, value) }
}

/// Supposed to return a debug flag. No-op in the final binary.
pub fn set_debug_flag2(flag_id: u32, value: u32) {
    // SAFETY: This is more or less an "atomic" operation.
    unsafe { ffi::SetDebugFlag2(flag_id, value) }
}

/// Unpatched this function will always returns true.
///
/// # Background information
/// This function seems to be a debug switch that the developers may have used to disable the
/// random enemy spawn.
/// If it returned false, the call to `[GlobalDungeonData::spawn_monster]` inside
/// `[GlobalDungeonData::try_spawn_monster_and_tick_spawn_counter]` would not be executed.
///
/// [GlobalDungeonData::spawn_monster]: crate::api::dungeon_mode::dungeon_struct::GlobalDungeonData::spawn_monster
/// [GlobalDungeonData::try_spawn_monster_and_tick_spawn_counter]: crate::api::dungeon_mode::dungeon_struct::GlobalDungeonData::try_spawn_monster_and_tick_spawn_counter
pub fn is_debug_flag_monster_spawns_enabled() -> bool {
    // SAFETY: This is more or less an "atomic" operation.
    unsafe { ffi::MonsterSpawnsEnabled() > 0 }
}