summaryrefslogtreecommitdiff
path: root/arm9/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arm9/lib')
-rw-r--r--arm9/lib/include/CARD_backup.h6
-rw-r--r--arm9/lib/include/CARD_common.h6
-rw-r--r--arm9/lib/include/CARD_pullOut.h6
-rw-r--r--arm9/lib/include/CARD_rom.h39
-rw-r--r--arm9/lib/include/CTRDG_common.h6
-rw-r--r--arm9/lib/include/DGT_common.h6
-rw-r--r--arm9/lib/include/DGT_dgt.h6
-rw-r--r--arm9/lib/include/FS_archive.h212
-rw-r--r--arm9/lib/include/FS_command.h11
-rw-r--r--arm9/lib/include/FS_file.h222
-rw-r--r--arm9/lib/include/FS_mw_dtor.h16
-rw-r--r--arm9/lib/include/FS_overlay.h71
-rw-r--r--arm9/lib/include/FS_rom.h14
-rw-r--r--arm9/lib/include/FSi_util.h46
-rw-r--r--arm9/lib/include/MB_mb.h45
-rw-r--r--arm9/lib/include/MI_byteAccess.h14
-rw-r--r--arm9/lib/include/MI_dma.h6
-rw-r--r--arm9/lib/include/MI_exMemory.h9
-rw-r--r--arm9/lib/include/MI_memory.h10
-rw-r--r--arm9/lib/include/MI_uncompress.h6
-rw-r--r--arm9/lib/include/OS_cache.h9
-rw-r--r--arm9/lib/include/OS_emulator.h13
-rw-r--r--arm9/lib/include/OS_init.h5
-rw-r--r--arm9/lib/include/OS_interrupt.h30
-rw-r--r--arm9/lib/include/OS_printf.h15
-rw-r--r--arm9/lib/include/OS_reset.h20
-rw-r--r--arm9/lib/include/OS_spinLock.h2
-rw-r--r--arm9/lib/include/OS_system.h1
-rw-r--r--arm9/lib/include/OS_tcm.h12
-rw-r--r--arm9/lib/include/OS_terminate_proc.h11
-rw-r--r--arm9/lib/include/OS_thread.h16
-rw-r--r--arm9/lib/include/PAD_pad.h38
-rw-r--r--arm9/lib/include/PXI_fifo.h33
-rw-r--r--arm9/lib/include/SPI_pm.h38
-rw-r--r--arm9/lib/include/consts.h22
-rw-r--r--arm9/lib/include/fx.h18
-rw-r--r--arm9/lib/include/mmap.h4
-rw-r--r--arm9/lib/include/registers.h361
-rw-r--r--arm9/lib/src/FS_archive.c445
-rw-r--r--arm9/lib/src/FS_command.c75
-rw-r--r--arm9/lib/src/FS_command_default.c468
-rw-r--r--arm9/lib/src/FS_file.c242
-rw-r--r--arm9/lib/src/FS_overlay.c320
-rw-r--r--arm9/lib/src/FS_rom.c118
-rw-r--r--arm9/lib/src/FX_cp.c48
-rw-r--r--arm9/lib/src/FX_vec.c44
-rw-r--r--arm9/lib/src/OS_arena.c2
-rw-r--r--arm9/lib/src/OS_emulator.c18
-rw-r--r--arm9/lib/src/OS_init.c2
-rw-r--r--arm9/lib/src/OS_interrupt.c89
-rw-r--r--arm9/lib/src/OS_printf.c1248
-rw-r--r--arm9/lib/src/OS_reset.c62
-rw-r--r--arm9/lib/src/OS_system.c1
-rw-r--r--arm9/lib/src/OS_tcm.c13
-rw-r--r--arm9/lib/src/OS_terminate_proc.c21
55 files changed, 4540 insertions, 81 deletions
diff --git a/arm9/lib/include/CARD_backup.h b/arm9/lib/include/CARD_backup.h
new file mode 100644
index 00000000..de594beb
--- /dev/null
+++ b/arm9/lib/include/CARD_backup.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_CARD_BACKUP_H_
+#define NITRO_CARD_BACKUP_H_
+
+BOOL CARD_TryWaitBackupAsync(void);
+
+#endif //NITRO_CARD_BACKUP_H_
diff --git a/arm9/lib/include/CARD_common.h b/arm9/lib/include/CARD_common.h
new file mode 100644
index 00000000..1396de12
--- /dev/null
+++ b/arm9/lib/include/CARD_common.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_CARD_COMMON_H_
+#define NITRO_CARD_COMMON_H_
+
+void CARD_Init(void);
+
+#endif //NITRO_CARD_COMMON_H_
diff --git a/arm9/lib/include/CARD_pullOut.h b/arm9/lib/include/CARD_pullOut.h
new file mode 100644
index 00000000..4a64f5ae
--- /dev/null
+++ b/arm9/lib/include/CARD_pullOut.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_CARD_PULLOUT_H_
+#define NITRO_CARD_PULLOUT_H_
+
+BOOL CARD_IsPulledOut(void);
+
+#endif //NITRO_CARD_PULLOUT_H_
diff --git a/arm9/lib/include/CARD_rom.h b/arm9/lib/include/CARD_rom.h
new file mode 100644
index 00000000..4c2e9dd5
--- /dev/null
+++ b/arm9/lib/include/CARD_rom.h
@@ -0,0 +1,39 @@
+#ifndef NITRO_CARD_ROM_H_
+#define NITRO_CARD_ROM_H_
+
+#include "MI_exMemory.h"
+#include "MI_dma.h"
+
+typedef struct
+{
+ u32 offset;
+ u32 length;
+}
+CARDRomRegion;
+
+static inline const CARDRomRegion * CARD_GetRomRegionOVT(MIProcessor target)
+{
+ return (target == MI_PROCESSOR_ARM9)
+ ? (const CARDRomRegion *)((const u8 *)HW_ROM_HEADER_BUF + 0x50)
+ : (const CARDRomRegion *)((const u8 *)HW_ROM_HEADER_BUF + 0x58);
+}
+
+void CARDi_ReadRom(u32 dma, const void * src, void * dst, u32 len, MIDmaCallback done_cb, void * arg, BOOL is_async);
+
+static inline void CARD_ReadRomAsync(u32 dma, const void * src, void * dst, u32 len, MIDmaCallback callback, void * arg)
+{
+ CARDi_ReadRom(dma, src, dst, len, callback, arg, TRUE);
+}
+
+void CARD_LockRom(u16 lock_id);
+void CARD_UnlockRom(u16 lock_id);
+
+static inline const CARDRomRegion * CARD_GetRomRegionFNT() {
+ return (const CARDRomRegion *)((const u8 *)HW_ROM_HEADER_BUF + 0x40);
+}
+
+static inline const CARDRomRegion * CARD_GetRomRegionFAT() {
+ return (const CARDRomRegion *)((const u8 *)HW_ROM_HEADER_BUF + 0x48);
+}
+
+#endif //NITRO_CARD_ROM_H_
diff --git a/arm9/lib/include/CTRDG_common.h b/arm9/lib/include/CTRDG_common.h
new file mode 100644
index 00000000..c83602b8
--- /dev/null
+++ b/arm9/lib/include/CTRDG_common.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_CTRDG_COMMON_H_
+#define NITRO_CTRDG_COMMON_H_
+
+BOOL CTRDG_IsPulledOut(void);
+
+#endif //NITRO_CTRDG_COMMON_H_
diff --git a/arm9/lib/include/DGT_common.h b/arm9/lib/include/DGT_common.h
new file mode 100644
index 00000000..c74ae7cd
--- /dev/null
+++ b/arm9/lib/include/DGT_common.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_DGT_COMMON_H_
+#define NITRO_DGT_COMMON_H_
+
+#define DGT_HASH2_DIGEST_SIZE (160/8)
+
+#endif //NITRO_DGT_COMMON_H_
diff --git a/arm9/lib/include/DGT_dgt.h b/arm9/lib/include/DGT_dgt.h
new file mode 100644
index 00000000..1c48531c
--- /dev/null
+++ b/arm9/lib/include/DGT_dgt.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_DGT_DGT_H_
+#define NITRO_DGT_DGT_H_
+
+void DGT_Hash2CalcHmac(void* digest, void* bin_ptr, int bin_len, void* key_ptr, int keylen);
+
+#endif //NITRO_DGT_DGT_H_
diff --git a/arm9/lib/include/FS_archive.h b/arm9/lib/include/FS_archive.h
new file mode 100644
index 00000000..d30081d7
--- /dev/null
+++ b/arm9/lib/include/FS_archive.h
@@ -0,0 +1,212 @@
+#ifndef NITRO_FS_ARCHIVE_H_
+#define NITRO_FS_ARCHIVE_H_
+
+#include "nitro.h"
+
+#include "OS_thread.h"
+
+struct FSFile;
+struct FSArchive;
+
+#define FS_ARCHIVE_NAME_LEN_MAX 3
+
+#define FS_ARCHIVE_FLAG_REGISTER 0x00000001
+#define FS_ARCHIVE_FLAG_LOADED 0x00000002
+#define FS_ARCHIVE_FLAG_TABLE_LOAD 0x00000004
+#define FS_ARCHIVE_FLAG_SUSPEND 0x00000008
+#define FS_ARCHIVE_FLAG_RUNNING 0x00000010
+#define FS_ARCHIVE_FLAG_CANCELING 0x00000020
+#define FS_ARCHIVE_FLAG_SUSPENDING 0x00000040
+#define FS_ARCHIVE_FLAG_UNLOADING 0x00000080
+#define FS_ARCHIVE_FLAG_IS_ASYNC 0x00000100
+#define FS_ARCHIVE_FLAG_IS_SYNC 0x00000200
+
+typedef enum {
+ FS_COMMAND_ASYNC_BEGIN = 0,
+ FS_COMMAND_READFILE = FS_COMMAND_ASYNC_BEGIN,
+ FS_COMMAND_WRITEFILE,
+ FS_COMMAND_ASYNC_END,
+
+ FS_COMMAND_SYNC_BEGIN = FS_COMMAND_ASYNC_END,
+ FS_COMMAND_SEEKDIR = FS_COMMAND_SYNC_BEGIN,
+ FS_COMMAND_READDIR,
+ FS_COMMAND_FINDPATH,
+ FS_COMMAND_GETPATH,
+ FS_COMMAND_OPENFILEFAST,
+ FS_COMMAND_OPENFILEDIRECT,
+ FS_COMMAND_CLOSEFILE,
+ FS_COMMAND_SYNC_END,
+
+ FS_COMMAND_STATUS_BEGIN = FS_COMMAND_SYNC_END,
+ FS_COMMAND_ACTIVATE = FS_COMMAND_STATUS_BEGIN,
+ FS_COMMAND_IDLE,
+ FS_COMMAND_SUSPEND,
+ FS_COMMAND_RESUME,
+ FS_COMMAND_STATUS_END,
+
+ FS_COMMAND_INVALID
+} FSCommandType;
+
+/* Asynchronous commands*/
+#define FS_ARCHIVE_PROC_READFILE (1 << FS_COMMAND_READFILE)
+#define FS_ARCHIVE_PROC_WRITEFILE (1 << FS_COMMAND_WRITEFILE)
+/* All asynchronous commands*/
+#define FS_ARCHIVE_PROC_ASYNC \
+ (FS_ARCHIVE_PROC_READFILE | FS_ARCHIVE_PROC_WRITEFILE)
+
+/* Synchronous commands*/
+#define FS_ARCHIVE_PROC_SEEKDIR (1 << FS_COMMAND_SEEKDIR)
+#define FS_ARCHIVE_PROC_READDIR (1 << FS_COMMAND_READDIR)
+#define FS_ARCHIVE_PROC_FINDPATH (1 << FS_COMMAND_FINDPATH)
+#define FS_ARCHIVE_PROC_GETPATH (1 << FS_COMMAND_GETPATH)
+#define FS_ARCHIVE_PROC_OPENFILEFAST (1 << FS_COMMAND_OPENFILEFAST)
+#define FS_ARCHIVE_PROC_OPENFILEDIRECT (1 << FS_COMMAND_OPENFILEDIRECT)
+#define FS_ARCHIVE_PROC_CLOSEFILE (1 << FS_COMMAND_CLOSEFILE)
+/* All synchronous commands*/
+#define FS_ARCHIVE_PROC_SYNC \
+ (FS_ARCHIVE_PROC_SEEKDIR | FS_ARCHIVE_PROC_READDIR | \
+ FS_ARCHIVE_PROC_FINDPATH | FS_ARCHIVE_PROC_GETPATH | \
+ FS_ARCHIVE_PROC_OPENFILEFAST | FS_ARCHIVE_PROC_OPENFILEDIRECT | FS_ARCHIVE_PROC_CLOSEFILE)
+
+/* Messages when status changes*/
+#define FS_ARCHIVE_PROC_ACTIVATE (1 << FS_COMMAND_ACTIVATE)
+#define FS_ARCHIVE_PROC_IDLE (1 << FS_COMMAND_IDLE)
+#define FS_ARCHIVE_PROC_SUSPENDING (1 << FS_COMMAND_SUSPEND)
+#define FS_ARCHIVE_PROC_RESUME (1 << FS_COMMAND_RESUME)
+/* All messages when status changes*/
+#define FS_ARCHIVE_PROC_STATUS \
+ (FS_ARCHIVE_PROC_ACTIVATE | FS_ARCHIVE_PROC_IDLE | \
+ FS_ARCHIVE_PROC_SUSPENDING | FS_ARCHIVE_PROC_RESUME)
+
+#define FS_ARCHIVE_PROC_ALL (~0)
+
+typedef enum {
+ FS_RESULT_SUCCESS = 0,
+ FS_RESULT_FAILURE,
+ FS_RESULT_BUSY,
+ FS_RESULT_CANCELED,
+ FS_RESULT_CANCELLED = FS_RESULT_CANCELED, // SDK alias
+ FS_RESULT_UNSUPPORTED,
+ FS_RESULT_ERROR,
+ FS_RESULT_PROC_ASYNC,
+ FS_RESULT_PROC_DEFAULT,
+ FS_RESULT_PROC_UNKNOWN
+}
+FSResult;
+
+typedef FSResult (*FS_ARCHIVE_READ_FUNC) (struct FSArchive *p, void *dst, u32 pos, u32 size);
+typedef FSResult (*FS_ARCHIVE_WRITE_FUNC) (struct FSArchive *p, const void *src, u32 pos, u32 size);
+typedef FSResult (*FS_ARCHIVE_PROC_FUNC) (struct FSFile *, FSCommandType);
+
+typedef struct
+{
+ struct FSFile * prev;
+ struct FSFile * next;
+}
+FSFileLink;
+
+typedef struct
+{
+ u32 start;
+ u16 index;
+ u16 parent;
+} FSArchiveFNT;
+
+typedef struct
+{
+ u32 top;
+ u32 bottom;
+} FSArchiveFAT;
+
+typedef struct FSArchive
+{
+ union
+ {
+ char ptr[4];
+ u32 pack;
+ } name;
+ struct FSArchive * next;
+ struct FSArchive * prev;
+ OSThreadQueue sync_q;
+ OSThreadQueue stat_q;
+ u32 flag;
+ FSFileLink list;
+ u32 base;
+ u32 fat;
+ u32 fat_size;
+ u32 fnt;
+ u32 fnt_size;
+ u32 fat_bak;
+ u32 fnt_bak;
+ void * load_mem;
+ FS_ARCHIVE_READ_FUNC read_func;
+ FS_ARCHIVE_WRITE_FUNC write_func;
+ FS_ARCHIVE_READ_FUNC table_func;
+ FS_ARCHIVE_PROC_FUNC proc;
+ u32 proc_flag;
+} FSArchive;
+
+FSArchive * const FS_FindArchive(const char * path, int offset);
+
+static inline BOOL FS_IsArchiveLoaded(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_LOADED) ? TRUE : FALSE;
+}
+
+static inline u32 FS_GetArchiveOffset(const FSArchive * p_arc, u32 pos)
+{
+ return p_arc->base + pos;
+}
+
+static inline BOOL FSi_IsArchiveCanceling(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_CANCELING) != 0;
+}
+
+static inline BOOL FS_IsArchiveSuspended(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_SUSPEND) ? TRUE : FALSE;
+}
+
+static inline BOOL FSi_IsArchiveSuspending(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_SUSPENDING) != 0;
+}
+
+static inline BOOL FSi_IsArchiveRunning(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_RUNNING) != 0;
+}
+
+static inline BOOL FSi_IsArchiveUnloading(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_UNLOADING) != 0;
+}
+
+static inline BOOL FSi_IsArchiveAsync(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_IS_ASYNC) != 0;
+}
+
+static inline BOOL FSi_IsArchiveSync(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_IS_SYNC) != 0;
+}
+
+static inline BOOL FS_IsArchiveTableLoaded(volatile const FSArchive * p_arc)
+{
+ return (p_arc->flag & FS_ARCHIVE_FLAG_TABLE_LOAD) ? TRUE : FALSE;
+}
+
+BOOL FSi_SendCommand(struct FSFile * file, FSCommandType command);
+BOOL FSi_ExecuteSyncCommand(struct FSFile * file);
+BOOL FS_SuspendArchive(FSArchive * p_arc);
+BOOL FS_ResumeArchive(FSArchive * p_arc);
+void FS_NotifyArchiveAsyncEnd(FSArchive *p_arc, FSResult ret);
+BOOL FS_RegisterArchiveName(FSArchive * p_arc, const char * name, int name_len);
+void FS_InitArchive(FSArchive * p_arc);
+void FS_SetArchiveProc(struct FSArchive * p_arc, FS_ARCHIVE_PROC_FUNC proc, u32 flags);
+BOOL FS_LoadArchive(FSArchive * p_arc, u32 base, u32 fat, u32 fat_size, u32 fnt, u32 fnt_size, FS_ARCHIVE_READ_FUNC read_func, FS_ARCHIVE_WRITE_FUNC write_func);
+u32 FS_LoadArchiveTables(FSArchive *p_arc, void *p_mem, u32 max_size);
+
+#endif //NITRO_FS_ARCHIVE_H_
diff --git a/arm9/lib/include/FS_command.h b/arm9/lib/include/FS_command.h
new file mode 100644
index 00000000..b5e73bcf
--- /dev/null
+++ b/arm9/lib/include/FS_command.h
@@ -0,0 +1,11 @@
+#ifndef NITRO_FS_COMMAND_H_
+#define NITRO_FS_COMMAND_H_
+
+#include "FS_file.h"
+
+extern FSResult (*const fsi_default_command[])(FSFile *);
+
+void FSi_ReleaseCommand(FSFile * file, FSResult signal);
+FSResult FSi_TranslateCommand(FSFile * file, FSCommandType command);
+
+#endif //NITRO_FS_COMMAND_H_
diff --git a/arm9/lib/include/FS_file.h b/arm9/lib/include/FS_file.h
new file mode 100644
index 00000000..3a7d8730
--- /dev/null
+++ b/arm9/lib/include/FS_file.h
@@ -0,0 +1,222 @@
+#ifndef NITRO_FS_FILE_H_
+#define NITRO_FS_FILE_H_
+
+#include "nitro.h"
+
+#include "FS_archive.h"
+
+#define FS_FILE_STATUS_BUSY 0x00000001
+#define FS_FILE_STATUS_CANCEL 0x00000002
+#define FS_FILE_STATUS_SYNC 0x00000004
+#define FS_FILE_STATUS_ASYNC 0x00000008
+#define FS_FILE_STATUS_IS_FILE 0x00000010
+#define FS_FILE_STATUS_IS_DIR 0x00000020
+#define FS_FILE_STATUS_OPERATING 0x00000040
+
+#define FS_FILE_NAME_MAX 127
+
+typedef enum FSSeekFileMode
+{
+ FS_SEEK_SET = 0,
+ FS_SEEK_CUR,
+ FS_SEEK_END
+} FSSeekFileMode;
+
+struct FSFile;
+
+#define FS_DMA_NOT_USE ((u32)~0)
+
+typedef struct FSDirPos
+{
+ struct FSArchive *arc;
+ u16 own_id;
+ u16 index;
+ u32 pos;
+}
+FSDirPos;
+
+typedef struct FSFileID
+{
+ struct FSArchive *arc;
+ u32 file_id;
+}
+FSFileID;
+
+typedef struct
+{
+ union
+ {
+ FSFileID file_id;
+ FSDirPos dir_id;
+ };
+ u32 is_directory;
+ u32 name_len;
+ char name[128];
+}
+FSDirEntry;
+
+
+typedef struct
+{
+ FSDirPos pos;
+}
+FSSeekDirInfo;
+
+
+typedef struct
+{
+ FSDirEntry *p_entry;
+ BOOL skip_string;
+}
+FSReadDirInfo;
+
+
+typedef struct
+{
+ FSDirPos pos;
+ const char *path;
+ BOOL find_directory;
+ union
+ {
+ FSFileID *file;
+ FSDirPos *dir;
+ }
+ result;
+}
+FSFindPathInfo;
+
+
+typedef struct
+{
+ u8 *buf;
+ u32 buf_len;
+ u16 total_len;
+ u16 dir_id;
+}
+FSGetPathInfo;
+
+
+typedef struct
+{
+ FSFileID id;
+}
+FSOpenFileFastInfo;
+
+
+typedef struct
+{
+ u32 top;
+ u32 bottom;
+ u32 index;
+}
+FSOpenFileDirectInfo;
+
+
+typedef struct
+{
+ u32 reserved;
+}
+FSCloseFileInfo;
+
+
+typedef struct
+{
+ void *dst;
+ u32 len_org;
+ u32 len;
+}
+FSReadFileInfo;
+
+
+typedef struct
+{
+ const void *src;
+ u32 len_org;
+ u32 len;
+}
+FSWriteFileInfo;
+
+typedef struct FSFile
+{
+ FSFileLink link;
+ struct FSArchive *arc;
+ u32 stat;
+ FSCommandType command;
+ FSResult error;
+ OSThreadQueue queue[1];
+ union {
+ struct
+ {
+ u32 own_id;
+ u32 top;
+ u32 bottom;
+ u32 pos;
+ } file;
+ struct
+ {
+ FSDirPos pos;
+ u32 parent;
+ } dir;
+ } prop;
+
+ union {
+ FSReadFileInfo readfile;
+ FSWriteFileInfo writefile;
+
+ FSSeekDirInfo seekdir;
+ FSReadDirInfo readdir;
+ FSFindPathInfo findpath;
+ FSGetPathInfo getpath;
+ FSOpenFileFastInfo openfilefast;
+ FSOpenFileDirectInfo openfiledirect;
+ FSCloseFileInfo closefile;
+ } arg;
+}
+FSFile;
+
+u32 FS_SetDefaultDMA(u32 dma_no); // returns the previous selection
+void FS_InitFile(FSFile * p_file);
+BOOL FS_WaitAsync(FSFile * p_file);
+BOOL FS_OpenFileDirect(FSFile * p_file, FSArchive * p_arc, u32 image_top, u32 image_bottom, u32 file_index);
+int FS_ReadFile(FSFile * p_file, void * dst, s32 len);
+int FS_ReadFileAsync(FSFile * p_file, void * dst, s32 len);
+BOOL FS_OpenFile(FSFile * p_file, const char * path);
+BOOL FS_OpenFileFast(FSFile * p_file, FSFileID file_id);
+BOOL FS_CloseFile(FSFile * p_file);
+BOOL FS_SeekFile(FSFile * p_file, int offset, FSSeekFileMode origin);
+
+static inline u32 const FS_GetFileImageTop(volatile const FSFile * p_file) {
+ return p_file->prop.file.top;
+}
+
+static inline u32 const FS_GetLength(volatile const FSFile * p_file)
+{
+ return p_file->prop.file.bottom - p_file->prop.file.top;
+}
+
+static inline BOOL FS_IsCanceling(volatile const FSFile * p_file)
+{
+ return (p_file->stat & FS_FILE_STATUS_CANCEL) ? TRUE : FALSE;
+}
+
+static inline BOOL FS_IsFileSyncMode(volatile const FSFile * p_file)
+{
+ return (p_file->stat & FS_FILE_STATUS_SYNC) ? TRUE : FALSE;
+}
+
+static inline BOOL FS_IsBusy(volatile const FSFile * p_file)
+{
+ return p_file->stat & FS_FILE_STATUS_BUSY ? TRUE : FALSE;
+}
+
+static inline BOOL FS_IsSucceeded(volatile const FSFile * p_file)
+{
+ return (p_file->error == FS_RESULT_SUCCESS) ? TRUE : FALSE;
+}
+
+static inline BOOL FS_IsDir(volatile const FSFile * p_file)
+{
+ return (p_file->stat & FS_FILE_STATUS_IS_DIR) ? TRUE : FALSE;
+}
+
+#endif //NITRO_FS_FILE_H_
diff --git a/arm9/lib/include/FS_mw_dtor.h b/arm9/lib/include/FS_mw_dtor.h
new file mode 100644
index 00000000..a746ed19
--- /dev/null
+++ b/arm9/lib/include/FS_mw_dtor.h
@@ -0,0 +1,16 @@
+#ifndef NITRO_FS_MW_DTOR_H_
+#define NITRO_FS_MW_DTOR_H_
+
+typedef void (*MWI_DESTRUCTOR_FUNC) (void *);
+
+typedef struct MWiDestructorChain
+{
+ struct MWiDestructorChain *next;
+ MWI_DESTRUCTOR_FUNC dtor;
+ void *obj;
+}
+MWiDestructorChain;
+
+extern MWiDestructorChain *__global_destructor_chain;
+
+#endif //NITRO_FS_MW_DTOR_H_
diff --git a/arm9/lib/include/FS_overlay.h b/arm9/lib/include/FS_overlay.h
new file mode 100644
index 00000000..14c7ce66
--- /dev/null
+++ b/arm9/lib/include/FS_overlay.h
@@ -0,0 +1,71 @@
+#ifndef NITRO_FS_OVERLAY_H_
+#define NITRO_FS_OVERLAY_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "nitro.h"
+#include "MI_exMemory.h"
+#include "FS_file.h"
+#include "CARD_rom.h"
+
+typedef u32 FSOverlayID;
+
+#define FS_EXTERN_OVERLAY(name) extern u32 SDK_OVERLAY_ ## name ## _ID[1]
+#define FS_OVERLAY_ID(name) ((u32)&(SDK_OVERLAY_ ## name ## _ID))
+
+typedef void (*FSOverlayInitFunc)(void);
+
+typedef struct FSOverlayInfoHeader
+{
+ u32 id;
+ u8 *ram_address;
+ u32 ram_size;
+ u32 bss_size;
+ FSOverlayInitFunc *sinit_init;
+ FSOverlayInitFunc *sinit_init_end;
+ u32 file_id;
+ u32 compressed: 24;
+ u32 flag: 8;
+} FSOverlayInfoHeader;
+
+typedef struct FSOverlayInfo
+{
+ FSOverlayInfoHeader header;
+ MIProcessor target;
+ CARDRomRegion file_pos;
+} FSOverlayInfo;
+
+static inline u8 *const FS_GetOverlayAddress(FSOverlayInfo *p_ovi)
+{
+ return p_ovi->header.ram_address;
+}
+
+static inline u32 const FS_GetOverlayImageSize(FSOverlayInfo *p_ovi)
+{
+ return p_ovi->header.ram_size;
+}
+
+static inline u32 const FS_GetOverlayTotalSize(FSOverlayInfo *p_ovi)
+{
+ return p_ovi->header.ram_size + p_ovi->header.bss_size;
+}
+
+BOOL FS_LoadOverlayInfo(FSOverlayInfo *p_ovi, MIProcessor target, FSOverlayID id);
+
+BOOL FS_LoadOverlay(MIProcessor target, FSOverlayID id);
+
+BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id);
+
+BOOL FS_LoadOverlayImage(FSOverlayInfo *p_ovi);
+
+void FS_StartOverlay(FSOverlayInfo *p_ovi);
+
+BOOL FS_LoadOverlayImageAsync(FSOverlayInfo *p_ovi, FSFile *p_file);
+
+#if defined(__cplusplus)
+};
+#endif
+
+#endif //NITRO_FS_OVERLAY_H_
diff --git a/arm9/lib/include/FS_rom.h b/arm9/lib/include/FS_rom.h
new file mode 100644
index 00000000..ac8ad8fb
--- /dev/null
+++ b/arm9/lib/include/FS_rom.h
@@ -0,0 +1,14 @@
+#ifndef NITRO_FS_ROM_H_
+#define NITRO_FS_ROM_H_
+
+#include "FS_archive.h"
+#include "CARD_rom.h"
+
+extern FSArchive fsi_arc_rom;
+extern s32 fsi_card_lock_id;
+extern CARDRomRegion fsi_ovt7;
+extern CARDRomRegion fsi_ovt9;
+
+void FSi_InitRom(u32 default_dma_no);
+
+#endif //NITRO_FS_ROM_H_
diff --git a/arm9/lib/include/FSi_util.h b/arm9/lib/include/FSi_util.h
new file mode 100644
index 00000000..6e96681e
--- /dev/null
+++ b/arm9/lib/include/FSi_util.h
@@ -0,0 +1,46 @@
+#ifndef NITRO_FSI_UTIL_H_
+#define NITRO_FSI_UTIL_H_
+
+#define ALIGN_MASK(a) ((u32)((a) - 1))
+
+#define ALIGN_BYTE(n, a) (((u32)(n) + ALIGN_MASK(a)) & ~ALIGN_MASK(a))
+
+#define BIT_MASK(a) ((u32)((1 << (a)) - 1))
+
+static inline BOOL FSi_IsSlash(u32 c)
+{
+ return (c == '/') || (c == '\\');
+}
+
+static inline void FSi_CutFromListCore(FSFileLink *trg)
+{
+ FSFile *const pr = trg->prev;
+ FSFile *const nx = trg->next;
+ if (pr)
+ pr->link.next = nx;
+ if (nx)
+ nx->link.prev = pr;
+}
+
+static inline void FSi_CutFromList(FSFile *elem)
+{
+ FSFileLink *const trg = &elem->link;
+ FSi_CutFromListCore(trg);
+ trg->next = trg->prev = NULL;
+}
+
+static inline void FSi_AppendToList(FSFile *elem, FSFile *list)
+{
+ FSFileLink *const trg = &elem->link;
+ FSi_CutFromListCore(trg);
+ {
+ while (list->link.next)
+ list = list->link.next;
+ list->link.next = elem;
+ trg->prev = list;
+ trg->next = NULL;
+ }
+}
+
+
+#endif //NITRO_FSI_UTIL_H_
diff --git a/arm9/lib/include/MB_mb.h b/arm9/lib/include/MB_mb.h
new file mode 100644
index 00000000..128ea480
--- /dev/null
+++ b/arm9/lib/include/MB_mb.h
@@ -0,0 +1,45 @@
+//
+// Created by red031000 on 2020-05-06.
+//
+
+#ifndef POKEDIAMOND_MB_MB_H
+#define POKEDIAMOND_MB_MB_H
+
+#include "consts.h"
+
+#define MB_TYPE_ILLEGAL 0
+#define MB_TYPE_NORMAL 1
+#define MB_TYPE_MULTIBOOT 2
+
+typedef struct {
+ u16 length;
+ u16 rssi;
+ u16 bssid[3];
+ u16 ssidLength;
+ u8 ssid[32];
+ u16 capaInfo;
+ struct {
+ u16 basic;
+ u16 support;
+ } rateSet;
+ u16 beaconperiod;
+ u16 dtimPeriod;
+ u16 channel;
+ u16 cfpPeriod;
+ u16 cfpMaxDuration;
+} MBParentBssDesc;
+
+typedef struct {
+ u16 boot_type;
+ MBParentBssDesc parent_bss_desc;
+} MBParam;
+
+static inline const MBParam *MB_GetMultiBootParam() {
+ return (const MBParam *)HW_WM_BOOT_BUF;
+}
+
+static inline BOOL MB_IsMultiBootChild() {
+ return MB_GetMultiBootParam()->boot_type == MB_TYPE_MULTIBOOT;
+}
+
+#endif //POKEDIAMOND_MB_MB_H
diff --git a/arm9/lib/include/MI_byteAccess.h b/arm9/lib/include/MI_byteAccess.h
new file mode 100644
index 00000000..cad4d518
--- /dev/null
+++ b/arm9/lib/include/MI_byteAccess.h
@@ -0,0 +1,14 @@
+#ifndef NITRO_MI_BYTEACCESS_H_
+#define NITRO_MI_BYTEACCESS_H_
+
+static inline u8 MI_ReadByte(const void *address)
+{
+ return *(u8 *)address;
+}
+
+static inline void MI_WriteByte(void *address, u8 value)
+{
+ *(u8 *)address = value;
+}
+
+#endif //NITRO_MI_BYTEACCESS_H_
diff --git a/arm9/lib/include/MI_dma.h b/arm9/lib/include/MI_dma.h
new file mode 100644
index 00000000..eddcedbb
--- /dev/null
+++ b/arm9/lib/include/MI_dma.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_MI_DMA_H_
+#define NITRO_MI_DMA_H_
+
+typedef void (*MIDmaCallback)(void *);
+
+#endif //NITRO_MI_DMA_H_
diff --git a/arm9/lib/include/MI_exMemory.h b/arm9/lib/include/MI_exMemory.h
new file mode 100644
index 00000000..4a8a10a8
--- /dev/null
+++ b/arm9/lib/include/MI_exMemory.h
@@ -0,0 +1,9 @@
+#ifndef NITRO_MI_EXMEMORY_H_
+#define NITRO_MI_EXMEMORY_H_
+
+typedef enum {
+ MI_PROCESSOR_ARM9 = 0,
+ MI_PROCESSOR_ARM7 = 1
+} MIProcessor;
+
+#endif //NITRO_MI_EXMEMORY_H_
diff --git a/arm9/lib/include/MI_memory.h b/arm9/lib/include/MI_memory.h
new file mode 100644
index 00000000..d9935a5f
--- /dev/null
+++ b/arm9/lib/include/MI_memory.h
@@ -0,0 +1,10 @@
+#ifndef NITRO_MI_MEMORY_H_
+#define NITRO_MI_MEMORY_H_
+
+void MI_CpuFill8(void *dest, u8 data, u32 size);
+void MI_CpuCopy8(void const *src, void *dest, u32 size);
+static inline void MI_CpuClear8(void *dest, u32 size) {
+ MI_CpuFill8(dest, 0, size);
+}
+
+#endif //NITRO_MI_MEMORY_H_
diff --git a/arm9/lib/include/MI_uncompress.h b/arm9/lib/include/MI_uncompress.h
new file mode 100644
index 00000000..55f28e27
--- /dev/null
+++ b/arm9/lib/include/MI_uncompress.h
@@ -0,0 +1,6 @@
+#ifndef NITRO_MI_UNCOMPRESS_H_
+#define NITRO_MI_UNCOMPRESS_H_
+
+void MIi_UncompressBackward(void * bottom);
+
+#endif //NITRO_MI_UNCOMPRESS_H_
diff --git a/arm9/lib/include/OS_cache.h b/arm9/lib/include/OS_cache.h
new file mode 100644
index 00000000..bee42d45
--- /dev/null
+++ b/arm9/lib/include/OS_cache.h
@@ -0,0 +1,9 @@
+#ifndef NITRO_OS_CACHE_H_
+#define NITRO_OS_CACHE_H_
+
+void IC_InvalidateRange(void *startAddr, u32 nBytes);
+void IC_FlushRange(void *startAddr, u32 nBytes);
+void DC_InvalidateRange(void *startAddr, u32 nBytes);
+void DC_FlushRange(void *startAddr, u32 nBytes);
+
+#endif //NITRO_OS_CACHE_H_
diff --git a/arm9/lib/include/OS_emulator.h b/arm9/lib/include/OS_emulator.h
new file mode 100644
index 00000000..54105258
--- /dev/null
+++ b/arm9/lib/include/OS_emulator.h
@@ -0,0 +1,13 @@
+//
+// Created by red031000 on 2020-05-05.
+//
+
+#ifndef POKEDIAMOND_OS_EMULATOR_H
+#define POKEDIAMOND_OS_EMULATOR_H
+
+#include "consts.h"
+
+BOOL OS_IsRunOnEmulator();
+u32 OS_GetConsoleType();
+
+#endif //POKEDIAMOND_OS_EMULATOR_H
diff --git a/arm9/lib/include/OS_init.h b/arm9/lib/include/OS_init.h
index 1ff2837c..dd2b20c7 100644
--- a/arm9/lib/include/OS_init.h
+++ b/arm9/lib/include/OS_init.h
@@ -7,13 +7,18 @@
#include "types.h"
#include "consts.h"
+#include "OS_tcm.h"
#include "OS_spinLock.h"
#include "OS_thread.h"
#include "OS_protectionRegion.h"
#include "OS_entropy.h"
+#include "OS_emulator.h"
#include "OS_arena.h"
#include "OS_alloc.h"
#include "OS_system.h"
+#include "OS_terminate_proc.h"
+#include "OS_interrupt.h"
+#include "OS_reset.h"
void OS_Init();
diff --git a/arm9/lib/include/OS_interrupt.h b/arm9/lib/include/OS_interrupt.h
new file mode 100644
index 00000000..21ce2ea0
--- /dev/null
+++ b/arm9/lib/include/OS_interrupt.h
@@ -0,0 +1,30 @@
+//
+// Created by red031000 on 2020-05-07.
+//
+
+#ifndef POKEDIAMOND_OS_INTERRUPT_H
+#define POKEDIAMOND_OS_INTERRUPT_H
+
+#include "types.h"
+
+typedef void (*OSIrqFunction) (void);
+
+typedef struct
+{
+ void (*func) (void *);
+ u32 enable;
+ void* arg;
+} OSIrqCallbackInfo;
+
+typedef u32 OSIrqMask;
+
+extern OSIrqFunction OS_IRQTable[];
+extern OSIrqCallbackInfo OSi_IrqCallbackInfo[8];
+
+void OS_InitIrqTable();
+void OS_SetIrqFunction(OSIrqMask intrBit, OSIrqFunction function);
+OSIrqFunction OS_GetIrqFunction(OSIrqMask intrBit);
+void OSi_EnterDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg);
+void OSi_EnterTimerCallback(u32 timerNo, void (*callback) (void *), void *arg);
+
+#endif //POKEDIAMOND_OS_INTERRUPT_H
diff --git a/arm9/lib/include/OS_printf.h b/arm9/lib/include/OS_printf.h
new file mode 100644
index 00000000..7c2e09b4
--- /dev/null
+++ b/arm9/lib/include/OS_printf.h
@@ -0,0 +1,15 @@
+#ifndef NITRO_OS_PRINTF_H_
+#define NITRO_OS_PRINTF_H_
+
+#define OS_Warning( ... ) ((void)0)
+#define OS_TPanic(...) OS_Terminate()
+#define OS_TWarning(...) ((void)0)
+
+#include "types.h"
+
+s32 OS_SPrintf(s8 *buffer, const s8 *format, ...);
+s32 OS_VSPrintf(s8 *buffer, const s8 *format, void *args);
+s32 OS_SNPrintf(s8 *buffer, s32 bufsz, const s8 *format, ...);
+s32 OS_VSNPrintf(s8 *buffer, s32 bufsz, const s8 *format, void *args);
+
+#endif //NITRO_OS_PRINTF_H_
diff --git a/arm9/lib/include/OS_reset.h b/arm9/lib/include/OS_reset.h
new file mode 100644
index 00000000..c3b60c98
--- /dev/null
+++ b/arm9/lib/include/OS_reset.h
@@ -0,0 +1,20 @@
+//
+// Created by red031000 on 2020-05-06.
+//
+
+#ifndef POKEDIAMOND_OS_RESET_H
+#define POKEDIAMOND_OS_RESET_H
+
+#include "consts.h"
+#include "PXI_fifo.h"
+
+#define OS_PXI_COMMAND_MASK 0x7f00
+#define OS_PXI_COMMAND_SHIFT 8
+#define OS_PXI_COMMAND_RESET 0x10
+
+void OS_InitReset();
+void OSi_CommonCallback(PXIFifoTag tag, u32 data, BOOL err);
+void OSi_SendToPxi(u16 data);
+void OS_ResetSystem(u32 parameter);
+
+#endif //POKEDIAMOND_OS_RESET_H
diff --git a/arm9/lib/include/OS_spinLock.h b/arm9/lib/include/OS_spinLock.h
index b7f0a571..3bb8a1c2 100644
--- a/arm9/lib/include/OS_spinLock.h
+++ b/arm9/lib/include/OS_spinLock.h
@@ -11,4 +11,6 @@ typedef volatile struct OSLockWord {
u16 extension;
} OSLockWord;
+s32 OS_GetLockID(void);
+
#endif //POKEDIAMOND_OS_SPINLOCK_H
diff --git a/arm9/lib/include/OS_system.h b/arm9/lib/include/OS_system.h
index 93903315..794e16d2 100644
--- a/arm9/lib/include/OS_system.h
+++ b/arm9/lib/include/OS_system.h
@@ -5,6 +5,7 @@
#ifndef POKEDIAMOND_OS_SYSTEM_H
#define POKEDIAMOND_OS_SYSTEM_H
+#include "function_target.h"
#include "consts.h"
typedef enum {
diff --git a/arm9/lib/include/OS_tcm.h b/arm9/lib/include/OS_tcm.h
new file mode 100644
index 00000000..7112ca0e
--- /dev/null
+++ b/arm9/lib/include/OS_tcm.h
@@ -0,0 +1,12 @@
+//
+// Created by red031000 on 2020-05-05.
+//
+
+#ifndef POKEDIAMOND_OS_TCM_H
+#define POKEDIAMOND_OS_TCM_H
+
+#include "consts.h"
+
+u32 OS_GetDTCMAddress();
+
+#endif //POKEDIAMOND_OS_TCM_H
diff --git a/arm9/lib/include/OS_terminate_proc.h b/arm9/lib/include/OS_terminate_proc.h
new file mode 100644
index 00000000..26741e5d
--- /dev/null
+++ b/arm9/lib/include/OS_terminate_proc.h
@@ -0,0 +1,11 @@
+//
+// Created by red031000 on 2020-05-07.
+//
+
+#ifndef POKEDIAMOND_OS_TERMINATE_PROC_H
+#define POKEDIAMOND_OS_TERMINATE_PROC_H
+
+void OS_Terminate();
+void OS_Halt();
+
+#endif //POKEDIAMOND_OS_TERMINATE_PROC_H
diff --git a/arm9/lib/include/OS_thread.h b/arm9/lib/include/OS_thread.h
index 4fb70bf7..15cec0c9 100644
--- a/arm9/lib/include/OS_thread.h
+++ b/arm9/lib/include/OS_thread.h
@@ -7,6 +7,14 @@
typedef struct _OSThread OSThread;
+struct _OSThreadQueue
+{
+ OSThread *head;
+ OSThread *tail;
+};
+
+typedef struct _OSThreadQueue OSThreadQueue;
+
typedef struct OSThreadInfo {
u16 isNeedRescheduling;
u16 irqDepth;
@@ -20,4 +28,12 @@ struct _OSThread
u8 padding[0x80]; //todo: not the correct size but idfk
};
+void OS_SleepThread(OSThreadQueue * queue);
+void OS_WakeupThread(OSThreadQueue * queue);
+
+static inline void OS_InitThreadQueue(OSThreadQueue * queue)
+{
+ queue->head = queue->tail = NULL;
+}
+
#endif //POKEDIAMOND_OS_THREAD_H
diff --git a/arm9/lib/include/PAD_pad.h b/arm9/lib/include/PAD_pad.h
new file mode 100644
index 00000000..0cb8a6f0
--- /dev/null
+++ b/arm9/lib/include/PAD_pad.h
@@ -0,0 +1,38 @@
+#ifndef NITRO_PAD_PAD_H_
+#define NITRO_PAD_PAD_H_
+
+
+//================================================================================
+// BUTTONS
+
+//---- masked value
+#define PAD_PLUS_KEY_MASK 0x00f0 // mask : cross keys
+#define PAD_BUTTON_MASK 0x2f0f // mask : buttons
+#define PAD_DEBUG_BUTTON_MASK 0x2000 // mask : debug button
+#define PAD_ALL_MASK 0x2fff // mask : all buttons
+#define PAD_RCNTPORT_MASK 0x2c00 // mask : factors ARM7 can read from RCNT register
+#define PAD_KEYPORT_MASK 0x03ff // mask : factors ARM7/9 can read from KEY register
+
+#define PAD_DETECT_FOLD_MASK 0x8000 // mask : folding
+
+//---- button and key
+#define PAD_BUTTON_A 0x0001 // A
+#define PAD_BUTTON_B 0x0002 // B
+#define PAD_BUTTON_SELECT 0x0004 // SELECT
+#define PAD_BUTTON_START 0x0008 // START
+#define PAD_KEY_RIGHT 0x0010 // RIGHT of cross key
+#define PAD_KEY_LEFT 0x0020 // LEFT of cross key
+#define PAD_KEY_UP 0x0040 // UP of cross key
+#define PAD_KEY_DOWN 0x0080 // DOWN of cross key
+#define PAD_BUTTON_R 0x0100 // R
+#define PAD_BUTTON_L 0x0200 // L
+#define PAD_BUTTON_X 0x0400 // X
+#define PAD_BUTTON_Y 0x0800 // Y
+#define PAD_BUTTON_DEBUG 0x2000 // Debug button
+
+static inline BOOL PAD_DetectFold(void)
+{
+ return (BOOL)((*(vu16 *)HW_BUTTON_XY_BUF & PAD_DETECT_FOLD_MASK) >> 15);
+}
+
+#endif //NITRO_PAD_PAD_H_
diff --git a/arm9/lib/include/PXI_fifo.h b/arm9/lib/include/PXI_fifo.h
new file mode 100644
index 00000000..1d45dda2
--- /dev/null
+++ b/arm9/lib/include/PXI_fifo.h
@@ -0,0 +1,33 @@
+//
+// Created by red031000 on 2020-05-06.
+//
+
+#ifndef POKEDIAMOND_PXI_FIFO_H
+#define POKEDIAMOND_PXI_FIFO_H
+
+#include "function_target.h"
+
+ENUMS_ALWAYS_INT_ON
+typedef enum {
+ PXI_FIFO_TAG_EX = 0, // Extension format
+ PXI_FIFO_TAG_USER_0, // for application programmer, use it in free
+ PXI_FIFO_TAG_USER_1, // for application programmer, use it in free
+ PXI_FIFO_TAG_SYSTEM, // SDK inner usage
+ PXI_FIFO_TAG_NVRAM, // NVRAM
+ PXI_FIFO_TAG_RTC, // RTC
+ PXI_FIFO_TAG_TOUCHPANEL, // Touch Panel
+ PXI_FIFO_TAG_SOUND, // Sound
+ PXI_FIFO_TAG_PM, // Power Management
+ PXI_FIFO_TAG_MIC, // Microphone
+ PXI_FIFO_TAG_WM, // Wireless Manager
+ PXI_FIFO_TAG_FS, // File System
+ PXI_FIFO_TAG_OS, // OS
+ PXI_FIFO_TAG_CTRDG, // Cartridge
+ PXI_FIFO_TAG_CARD, // Card
+ PXI_FIFO_TAG_WVR, // Control driving wireless library
+ PXI_FIFO_TAG_CTRDG_Ex, // Cartridge Ex
+ PXI_MAX_FIFO_TAG = 32 // MAX FIFO TAG
+} PXIFifoTag;
+ENUMS_ALWAYS_INT_RESET
+
+#endif //POKEDIAMOND_PXI_FIFO_H
diff --git a/arm9/lib/include/SPI_pm.h b/arm9/lib/include/SPI_pm.h
new file mode 100644
index 00000000..b5063ed8
--- /dev/null
+++ b/arm9/lib/include/SPI_pm.h
@@ -0,0 +1,38 @@
+#ifndef NITRO_SPI_PM_H_
+#define NITRO_SPI_PM_H_
+
+ENUMS_ALWAYS_INT_ON
+
+#define PM_TRIGGER_KEY (1 << 0)
+#define PM_TRIGGER_RTC_ALARM (1 << 1)
+#define PM_TRIGGER_COVER_OPEN (1 << 2)
+#define PM_TRIGGER_CARD (1 << 3)
+#define PM_TRIGGER_CARTRIDGE (1 << 4)
+typedef u32 PMWakeUpTrigger;
+
+#define PM_PAD_LOGIC_OR (0 << REG_PAD_KEYCNT_LOGIC_SHIFT)
+#define PM_PAD_LOGIC_AND (1 << REG_PAD_KEYCNT_LOGIC_SHIFT)
+typedef u32 PMLogic;
+
+typedef enum
+{
+ PM_BACKLIGHT_OFF = 0,
+ PM_BACKLIGHT_ON = 1
+} PMBackLightSwitch;
+
+typedef enum
+{
+ PM_LCD_TOP = 0,
+ PM_LCD_BOTTOM = 1,
+ PM_LCD_ALL = 2
+}
+PMLCDTarget;
+
+void PM_GetBackLight(PMBackLightSwitch * top, PMBackLightSwitch * bottom);
+void PM_GoSleepMode(PMWakeUpTrigger trigger, PMLogic logic, u16 keyPattern);
+u32 PM_SetBackLight(PMLCDTarget target, PMBackLightSwitch status);
+void PM_ForceToPowerOff(void);
+
+ENUMS_ALWAYS_INT_RESET
+
+#endif //NITRO_SPI_PM_H_
diff --git a/arm9/lib/include/consts.h b/arm9/lib/include/consts.h
index e07fe323..b99b4148 100644
--- a/arm9/lib/include/consts.h
+++ b/arm9/lib/include/consts.h
@@ -6,6 +6,7 @@
#define POKEDIAMOND_CONSTS_H
#include "mmap.h"
+#include "registers.h"
#define HW_PSR_CPU_MODE_MASK 0x1f // CPU mode
@@ -13,19 +14,6 @@
#define HW_PSR_DISABLE_IRQ 0x80 // Disable IRQ
#define HW_PSR_DISABLE_IRQ_FIQ 0xc0 // Disable FIQ and IRQ
-#define HW_REG_BASE 0x04000000
-#define REG_VCOUNT_OFFSET 0x006
-#define REG_VCOUNT_ADDR (HW_REG_BASE + REG_VCOUNT_OFFSET)
-#define reg_GX_VCOUNT (*(REGType16v *)REG_VCOUNT_ADDR)
-
-#define REG_KEYINPUT_OFFSET 0x130
-#define REG_KEYINPUT_ADDR (HW_REG_BASE + REG_KEYINPUT_OFFSET)
-#define reg_PAD_KEYINPUT (*(REGType16v *)REG_KEYINPUT_ADDR)
-
-#define REG_GXSTAT_OFFSET 0x600
-#define REG_GXSTAT_ADDR (HW_REG_BASE + REG_GXSTAT_OFFSET)
-#define reg_G3X_GXSTAT (*(REGType32v *)REG_GXSTAT_ADDR)
-
#define HW_C6_PR_4KB 0x16
#define HW_C6_PR_8KB 0x18
#define HW_C6_PR_16KB 0x1a
@@ -48,9 +36,17 @@
#define HW_C6_PR_2GB 0x3c
#define HW_C6_PR_4GB 0x3e
+#define PXI_PROC_ARM7 0x01
+
+#define OSi_CONSOLE_NOT_DETECT 0xffffffff
+
+#define OS_CONSOLE_NITRO 0x80000000
+#define OS_CONSOLE_DEV_CARD 0x02000000
#define OS_CONSOLE_SIZE_MASK 0x00000003
#define OS_CONSOLE_SIZE_4MB 0x00000001
+#define OSi_TCM_REGION_BASE_MASK 0xfffff000
+
#define OSi_GetArenaInfo() (*(OSArenaInfo*)HW_ARENA_INFO_BUF)
#define OSi_TRUNC(n, a) (((u32) (n)) & ~((a) - 1))
#define OSi_ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1))
diff --git a/arm9/lib/include/fx.h b/arm9/lib/include/fx.h
index 7e74d079..b1c3aa88 100644
--- a/arm9/lib/include/fx.h
+++ b/arm9/lib/include/fx.h
@@ -46,24 +46,6 @@ typedef s64 fx64c;
#define FX64C_INT_ABS(x) FX_INT_ABS(FX64C, x)
#define FX64C_FRAC(x) FX_FRAC(FX64C, x)
-
-#define HW_REG_DIVCNT 0x04000280
-#define HW_REG_DIV_NUMER 0x04000290
-#define HW_REG_DIV_DENOM 0x04000298
-#define HW_REG_DIV_RESULT 0x040002A0
-#define HW_REG_DIVREM_RESULT 0x040002A8
-
-#define HW_REG_SQRTCNT 0x040002B0
-#define HW_REG_SQRT_RESULT 0x040002B4
-#define HW_REG_SQRT_PARAM 0x040002B8
-
-#define SETREG16(x, y) ((*(vu16 *)x) = y)
-#define SETREG32(x, y) ((*(vu32 *)x) = y)
-#define SETREG64(x, y) ((*(vu64 *)x) = y)
-#define READREG16(x) (*(vu16 *)x)
-#define READREG32(x) (*(vu32 *)x)
-#define READREG64(x) (*(vu64 *)x)
-
#define FX32_MUL(a, b) ((fx32)(((fx64)a * b) >> FX32_INT_SHIFT))
#define FX32_MUL_ADD_MUL(a, b, c, d) ((fx32)(((fx64)a * b + (fx64)c * d) >> FX32_INT_SHIFT))
//the extra term here is for rounding
diff --git a/arm9/lib/include/mmap.h b/arm9/lib/include/mmap.h
index d94df843..27255115 100644
--- a/arm9/lib/include/mmap.h
+++ b/arm9/lib/include/mmap.h
@@ -12,8 +12,10 @@ extern u32 SDK_AUTOLOAD_DTCM_START[];
#define HW_MAIN_MEM_SHARED_SIZE 0x00001000
#define HW_MAIN_MEM_DEBUGGER_OFFSET 0x00700000
+#define HW_ITCM_IMAGE 0x01000000
#define HW_ITCM 0x01FF8000
#define HW_ITCM_SIZE 0x00008000
+#define HW_ITCM_END (HW_ITCM + HW_ITCM_SIZE)
#define HW_WRAM 0x037F8000
@@ -23,6 +25,8 @@ extern u32 SDK_AUTOLOAD_DTCM_START[];
#define HW_CARD_ROM_HEADER_SIZE 0x00000160
#define HW_DOWNLOAD_PARAMETER_SIZE 0x00000020
+#define HW_RESET_PARAMETER_BUF (HW_MAIN_MEM + 0x007ffc20)
+#define HW_WM_BOOT_BUF (HW_MAIN_MEM + 0x007ffc40)
#define HW_ARENA_INFO_BUF (HW_MAIN_MEM + 0x007ffda0) // Arena data structure
#define HW_ROM_HEADER_BUF (HW_MAIN_MEM + 0x007ffe00) // ROM registration area data buffer
#define HW_RED_RESERVED (HW_MAIN_MEM + 0x007ff800) // Some kind of reserved data for shared memory
diff --git a/arm9/lib/include/registers.h b/arm9/lib/include/registers.h
new file mode 100644
index 00000000..d1cc7792
--- /dev/null
+++ b/arm9/lib/include/registers.h
@@ -0,0 +1,361 @@
+//
+// Created by red031000 on 2020-05-06.
+//
+
+#ifndef POKEDIAMOND_REGISTERS_H
+#define POKEDIAMOND_REGISTERS_H
+
+#include "types.h"
+
+#define reg_GX_DISPCNT (*(REGType32v *)0x4000000)
+#define reg_GX_DISPSTAT (*(REGType16v *)0x4000004)
+#define reg_GX_VCOUNT (*(REGType16v *)0x4000006)
+
+#define reg_G3X_DISP3DCNT (*(REGType16v *)0x4000060)
+
+#define reg_GX_DISPCAPCNT (*(REGType32v *)0x4000064)
+#define reg_GX_DISP_MMEM_FIFO (*(REGType32v *)0x4000068)
+#define reg_GX_DISP_MMEM_FIFO_L (*(REGType16v *)0x4000068)
+#define reg_GX_DISP_MMEM_FIFO_H (*(REGType16v *)0x400006a)
+#define reg_GX_MASTER_BRIGHT (*(REGType16v *)0x400006c)
+#define reg_GX_TVOUTCNT (*(REGType16v *)0x4000070)
+
+#define reg_MI_DMA0SAD (*(REGType32v *)0x40000b0)
+#define reg_MI_DMA0DAD (*(REGType32v *)0x40000b4)
+#define reg_MI_DMA0CNT (*(REGType32v *)0x40000b8)
+#define reg_MI_DMA1SAD (*(REGType32v *)0x40000bc)
+#define reg_MI_DMA1DAD (*(REGType32v *)0x40000c0)
+#define reg_MI_DMA1CNT (*(REGType32v *)0x40000c4)
+#define reg_MI_DMA2SAD (*(REGType32v *)0x40000c8)
+#define reg_MI_DMA2DAD (*(REGType32v *)0x40000cc)
+#define reg_MI_DMA2CNT (*(REGType32v *)0x40000d0)
+#define reg_MI_DMA3SAD (*(REGType32v *)0x40000d4)
+#define reg_MI_DMA3DAD (*(REGType32v *)0x40000d8)
+#define reg_MI_DMA3CNT (*(REGType32v *)0x40000dc)
+#define reg_MI_DMA0_CLR_DATA (*(REGType32v *)0x40000e0)
+#define reg_MI_DMA1_CLR_DATA (*(REGType32v *)0x40000e4)
+#define reg_MI_DMA2_CLR_DATA (*(REGType32v *)0x40000e8)
+#define reg_MI_DMA3_CLR_DATA (*(REGType32v *)0x40000ec)
+
+#define reg_PAD_KEYINPUT (*(REGType16v *)0x4000130)
+
+#define reg_MI_MCCNT0 (*(REGType16v *)0x40001a0)
+#define reg_MI_MCD0 (*(REGType16v *)0x40001a2)
+#define reg_MI_MCCNT1 (*(REGType32v *)0x40001a4)
+#define reg_MI_MCCMD0 (*(REGType32v *)0x40001a8)
+#define reg_MI_MCCMD1 (*(REGType32v *)0x40001ac)
+#define reg_MI_EXMEMCNT (*(REGType16v *)0x4000204)
+
+#define reg_GX_VRAMCNT (*(REGType32v *)0x4000240)
+#define reg_GX_VRAMCNT_A (*(REGType8v *)0x4000240)
+#define reg_GX_VRAMCNT_B (*(REGType8v *)0x4000241)
+#define reg_GX_VRAMCNT_C (*(REGType8v *)0x4000242)
+#define reg_GX_VRAMCNT_D (*(REGType8v *)0x4000243)
+#define reg_GX_WVRAMCNT (*(REGType32v *)0x4000244)
+#define reg_GX_VRAMCNT_E (*(REGType8v *)0x4000244)
+#define reg_GX_VRAMCNT_F (*(REGType8v *)0x4000245)
+#define reg_GX_VRAMCNT_G (*(REGType8v *)0x4000246)
+#define reg_GX_VRAMCNT_WRAM (*(REGType8v *)0x4000247)
+#define reg_GX_VRAM_HI_CNT (*(REGType16v *)0x4000248)
+#define reg_GX_VRAMCNT_H (*(REGType8v *)0x4000248)
+#define reg_GX_VRAMCNT_I (*(REGType8v *)0x4000249)
+
+#define reg_CP_DIVCNT (*(REGType16v *)0x4000280)
+#define reg_CP_DIV_NUMER (*(REGType64v *)0x4000290)
+#define reg_CP_DIV_DENOM (*(REGType64v *)0x4000298)
+#define reg_CP_DIV_RESULT (*(REGType64v *)0x40002A0)
+#define reg_CP_DIVREM_RESULT (*(REGType64v *)0x40002A8)
+#define reg_CP_SQRTCNT (*(REGType16v *)0x40002B0)
+#define reg_CP_SQRT_RESULT (*(REGType32v *)0x40002B4)
+#define reg_CP_SQRT_PARAM (*(REGType64v *)0x40002B8)
+
+#define reg_GX_POWCNT (*(REGType16v *)0x4000304)
+
+#define reg_G3X_RDLINES_COUNT (*(const REGType16v *)0x4000320)
+#define reg_G3X_EDGE_COLOR_0 (*(REGType32v *)0x4000330)
+#define reg_G3X_EDGE_COLOR_0_L (*(REGType16v *)0x4000330)
+#define reg_G3X_EDGE_COLOR_0_H (*(REGType16v *)0x4000332)
+#define reg_G3X_EDGE_COLOR_1 (*(REGType32v *)0x4000334)
+#define reg_G3X_EDGE_COLOR_1_L (*(REGType16v *)0x4000334)
+#define reg_G3X_EDGE_COLOR_1_H (*(REGType16v *)0x4000336)
+#define reg_G3X_EDGE_COLOR_2 (*(REGType32v *)0x4000338)
+#define reg_G3X_EDGE_COLOR_2_L (*(REGType16v *)0x4000338)
+#define reg_G3X_EDGE_COLOR_2_H (*(REGType16v *)0x400033a)
+#define reg_G3X_EDGE_COLOR_3 (*(REGType32v *)0x400033c)
+#define reg_G3X_EDGE_COLOR_3_L (*(REGType16v *)0x400033c)
+#define reg_G3X_EDGE_COLOR_3_H (*(REGType16v *)0x400033e)
+#define reg_G3X_ALPHA_TEST_REF (*(REGType16v *)0x4000340)
+#define reg_G3X_CLEAR_COLOR (*(REGType32v *)0x4000350)
+#define reg_G3X_CLEAR_DEPTH (*(REGType16v *)0x4000354)
+#define reg_G3X_CLRIMAGE_OFFSET (*(REGType16v *)0x4000356)
+#define reg_G3X_FOG_COLOR (*(REGType32v *)0x4000358)
+#define reg_G3X_FOG_OFFSET (*(REGType16v *)0x400035c)
+#define reg_G3X_FOG_TABLE_0 (*(REGType32v *)0x4000360)
+#define reg_G3X_FOG_TABLE_0_L (*(REGType16v *)0x4000360)
+#define reg_G3X_FOG_TABLE_0_H (*(REGType16v *)0x4000362)
+#define reg_G3X_FOG_TABLE_1 (*(REGType32v *)0x4000364)
+#define reg_G3X_FOG_TABLE_1_L (*(REGType16v *)0x4000364)
+#define reg_G3X_FOG_TABLE_1_H (*(REGType16v *)0x4000366)
+#define reg_G3X_FOG_TABLE_2 (*(REGType32v *)0x4000368)
+#define reg_G3X_FOG_TABLE_2_L (*(REGType16v *)0x4000368)
+#define reg_G3X_FOG_TABLE_2_H (*(REGType16v *)0x400036a)
+#define reg_G3X_FOG_TABLE_3 (*(REGType32v *)0x400036c)
+#define reg_G3X_FOG_TABLE_3_L (*(REGType16v *)0x400036c)
+#define reg_G3X_FOG_TABLE_3_H (*(REGType16v *)0x400036e)
+#define reg_G3X_FOG_TABLE_4 (*(REGType32v *)0x4000370)
+#define reg_G3X_FOG_TABLE_4_L (*(REGType16v *)0x4000370)
+#define reg_G3X_FOG_TABLE_4_H (*(REGType16v *)0x4000372)
+#define reg_G3X_FOG_TABLE_5 (*(REGType32v *)0x4000374)
+#define reg_G3X_FOG_TABLE_5_L (*(REGType16v *)0x4000374)
+#define reg_G3X_FOG_TABLE_5_H (*(REGType16v *)0x4000376)
+#define reg_G3X_FOG_TABLE_6 (*(REGType32v *)0x4000378)
+#define reg_G3X_FOG_TABLE_6_L (*(REGType16v *)0x4000378)
+#define reg_G3X_FOG_TABLE_6_H (*(REGType16v *)0x400037a)
+#define reg_G3X_FOG_TABLE_7 (*(REGType32v *)0x400037c)
+#define reg_G3X_FOG_TABLE_7_L (*(REGType16v *)0x400037c)
+#define reg_G3X_FOG_TABLE_7_H (*(REGType16v *)0x400037e)
+#define reg_G3X_TOON_TABLE_0 (*(REGType32v *)0x4000380)
+#define reg_G3X_TOON_TABLE_0_L (*(REGType16v *)0x4000380)
+#define reg_G3X_TOON_TABLE_0_H (*(REGType16v *)0x4000382)
+#define reg_G3X_TOON_TABLE_1 (*(REGType32v *)0x4000384)
+#define reg_G3X_TOON_TABLE_1_L (*(REGType16v *)0x4000384)
+#define reg_G3X_TOON_TABLE_1_H (*(REGType16v *)0x4000386)
+#define reg_G3X_TOON_TABLE_2 (*(REGType32v *)0x4000388)
+#define reg_G3X_TOON_TABLE_2_L (*(REGType16v *)0x4000388)
+#define reg_G3X_TOON_TABLE_2_H (*(REGType16v *)0x400038a)
+#define reg_G3X_TOON_TABLE_3 (*(REGType32v *)0x400038c)
+#define reg_G3X_TOON_TABLE_3_L (*(REGType16v *)0x400038c)
+#define reg_G3X_TOON_TABLE_3_H (*(REGType16v *)0x400038e)
+#define reg_G3X_TOON_TABLE_4 (*(REGType32v *)0x4000390)
+#define reg_G3X_TOON_TABLE_4_L (*(REGType16v *)0x4000390)
+#define reg_G3X_TOON_TABLE_4_H (*(REGType16v *)0x4000392)
+#define reg_G3X_TOON_TABLE_5 (*(REGType32v *)0x4000394)
+#define reg_G3X_TOON_TABLE_5_L (*(REGType16v *)0x4000394)
+#define reg_G3X_TOON_TABLE_5_H (*(REGType16v *)0x4000396)
+#define reg_G3X_TOON_TABLE_7 (*(REGType32v *)0x400039c)
+#define reg_G3X_TOON_TABLE_7_L (*(REGType16v *)0x400039c)
+#define reg_G3X_TOON_TABLE_7_H (*(REGType16v *)0x400039e)
+#define reg_G3X_TOON_TABLE_8 (*(REGType32v *)0x40003a0)
+#define reg_G3X_TOON_TABLE_8_L (*(REGType16v *)0x40003a0)
+#define reg_G3X_TOON_TABLE_8_H (*(REGType16v *)0x40003a2)
+#define reg_G3X_TOON_TABLE_9 (*(REGType32v *)0x40003a4)
+#define reg_G3X_TOON_TABLE_9_L (*(REGType16v *)0x40003a4)
+#define reg_G3X_TOON_TABLE_9_H (*(REGType16v *)0x40003a6)
+#define reg_G3X_TOON_TABLE_10 (*(REGType32v *)0x40003a8)
+#define reg_G3X_TOON_TABLE_10_L (*(REGType16v *)0x40003a8)
+#define reg_G3X_TOON_TABLE_10_H (*(REGType16v *)0x40003aa)
+#define reg_G3X_TOON_TABLE_11 (*(REGType32v *)0x40003ac)
+#define reg_G3X_TOON_TABLE_11_L (*(REGType16v *)0x40003ac)
+#define reg_G3X_TOON_TABLE_11_H (*(REGType16v *)0x40003ae)
+#define reg_G3X_TOON_TABLE_12 (*(REGType32v *)0x40003b0)
+#define reg_G3X_TOON_TABLE_12_L (*(REGType16v *)0x40003b0)
+#define reg_G3X_TOON_TABLE_12_H (*(REGType16v *)0x40003b2)
+#define reg_G3X_TOON_TABLE_13 (*(REGType32v *)0x40003b4)
+#define reg_G3X_TOON_TABLE_13_L (*(REGType16v *)0x40003b4)
+#define reg_G3X_TOON_TABLE_13_H (*(REGType16v *)0x40003b6)
+#define reg_G3X_TOON_TABLE_14 (*(REGType32v *)0x40003b8)
+#define reg_G3X_TOON_TABLE_14_L (*(REGType16v *)0x40003b8)
+#define reg_G3X_TOON_TABLE_14_H (*(REGType16v *)0x40003ba)
+#define reg_G3X_TOON_TABLE_15 (*(REGType32v *)0x40003bc)
+#define reg_G3X_TOON_TABLE_15_L (*(REGType16v *)0x40003bc)
+#define reg_G3X_TOON_TABLE_15_H (*(REGType16v *)0x40003be)
+#define reg_G3X_GXFIFO (*(REGType32v *)0x4000400)
+
+#define reg_G3_MTX_MODE (*(REGType32v *)0x4000440)
+#define reg_G3_MTX_PUSH (*(REGType32v *)0x4000444)
+#define reg_G3_MTX_POP (*(REGType32v *)0x4000448)
+#define reg_G3_MTX_STORE (*(REGType32v *)0x400044c)
+#define reg_G3_MTX_RESTORE (*(REGType32v *)0x4000450)
+#define reg_G3_MTX_IDENTITY (*(REGType32v *)0x4000454)
+#define reg_G3_MTX_LOAD_4x4 (*(REGType32v *)0x4000458)
+#define reg_G3_MTX_LOAD_4x3 (*(REGType32v *)0x400045c)
+#define reg_G3_MTX_MULT_4x4 (*(REGType32v *)0x4000460)
+#define reg_G3_MTX_MULT_4x3 (*(REGType32v *)0x4000464)
+#define reg_G3_MTX_MULT_3x3 (*(REGType32v *)0x4000468)
+#define reg_G3_MTX_SCALE (*(REGType32v *)0x400046c)
+#define reg_G3_MTX_TRANS (*(REGType32v *)0x4000470)
+#define reg_G3_COLOR (*(REGType32v *)0x4000480)
+#define reg_G3_NORMAL (*(REGType32v *)0x4000484)
+#define reg_G3_TEXCOORD (*(REGType32v *)0x4000488)
+#define reg_G3_VTX_16 (*(REGType32v *)0x400048c)
+#define reg_G3_VTX_10 (*(REGType32v *)0x4000490)
+#define reg_G3_VTX_XY (*(REGType32v *)0x4000494)
+#define reg_G3_VTX_XZ (*(REGType32v *)0x4000498)
+#define reg_G3_VTX_YZ (*(REGType32v *)0x400049c)
+#define reg_G3_VTX_DIFF (*(REGType32v *)0x40004a0)
+#define reg_G3_POLYGON_ATTR (*(REGType32v *)0x40004a4)
+#define reg_G3_TEXIMAGE_PARAM (*(REGType32v *)0x40004a8)
+#define reg_G3_TEXPLTT_BASE (*(REGType32v *)0x40004ac)
+#define reg_G3_DIF_AMB (*(REGType32v *)0x40004c0)
+#define reg_G3_SPE_EMI (*(REGType32v *)0x40004c4)
+#define reg_G3_LIGHT_VECTOR (*(REGType32v *)0x40004c8)
+#define reg_G3_LIGHT_COLOR (*(REGType32v *)0x40004cc)
+#define reg_G3_SHININESS (*(REGType32v *)0x40004d0)
+#define reg_G3_BEGIN_VTXS (*(REGType32v *)0x4000500)
+#define reg_G3_END_VTXS (*(REGType32v *)0x4000504)
+#define reg_G3_SWAP_BUFFERS (*(REGType32v *)0x4000540)
+#define reg_G3_VIEWPORT (*(REGType32v *)0x4000580)
+#define reg_G3_BOX_TEST (*(REGType32v *)0x40005c0)
+#define reg_G3_POS_TEST (*(REGType32v *)0x40005c4)
+#define reg_G3_VEC_TEST (*(REGType32v *)0x40005c8)
+
+#define reg_G3X_GXSTAT (*(REGType32v *)0x4000600)
+#define reg_G3X_LISTRAM_COUNT (*(REGType16v *)0x4000604)
+#define reg_G3X_VTXRAM_COUNT (*(REGType16v *)0x4000606)
+#define reg_G3X_DISP_1DOT_DEPTH (*(REGType16v *)0x4000610)
+#define reg_G3X_POS_RESULT_X (*(const REGType32v *)0x4000620)
+#define reg_G3X_POS_RESULT_Y (*(const REGType32v *)0x4000624)
+#define reg_G3X_POS_RESULT_Z (*(const REGType32v *)0x4000628)
+#define reg_G3X_POS_RESULT_W (*(const REGType32v *)0x400062c)
+#define reg_G3X_VEC_RESULT_X (*(const REGType16v *)0x4000630)
+#define reg_G3X_VEC_RESULT_Y (*(const REGType16v *)0x4000632)
+#define reg_G3X_VEC_RESULT_Z (*(const REGType16v *)0x4000634)
+#define reg_G3X_CLIPMTX_RESULT_0 (*(const REGType32v *)0x4000640)
+#define reg_G3X_CLIPMTX_RESULT_1 (*(const REGType32v *)0x4000644)
+#define reg_G3X_CLIPMTX_RESULT_2 (*(const REGType32v *)0x4000648)
+#define reg_G3X_CLIPMTX_RESULT_3 (*(const REGType32v *)0x400064c)
+#define reg_G3X_CLIPMTX_RESULT_4 (*(const REGType32v *)0x4000650)
+#define reg_G3X_CLIPMTX_RESULT_5 (*(const REGType32v *)0x4000654)
+#define reg_G3X_CLIPMTX_RESULT_6 (*(const REGType32v *)0x4000658)
+#define reg_G3X_CLIPMTX_RESULT_7 (*(const REGType32v *)0x400065c)
+#define reg_G3X_CLIPMTX_RESULT_8 (*(const REGType32v *)0x4000660)
+#define reg_G3X_CLIPMTX_RESULT_9 (*(const REGType32v *)0x4000664)
+#define reg_G3X_CLIPMTX_RESULT_10 (*(const REGType32v *)0x4000668)
+#define reg_G3X_CLIPMTX_RESULT_11 (*(const REGType32v *)0x400066c)
+#define reg_G3X_CLIPMTX_RESULT_12 (*(const REGType32v *)0x4000670)
+#define reg_G3X_CLIPMTX_RESULT_13 (*(const REGType32v *)0x4000674)
+#define reg_G3X_CLIPMTX_RESULT_14 (*(const REGType32v *)0x4000678)
+#define reg_G3X_CLIPMTX_RESULT_15 (*(const REGType32v *)0x400067c)
+#define reg_G3X_VECMTX_RESULT_0 (*(const REGType32v *)0x4000680)
+#define reg_G3X_VECMTX_RESULT_1 (*(const REGType32v *)0x4000684)
+#define reg_G3X_VECMTX_RESULT_2 (*(const REGType32v *)0x4000688)
+#define reg_G3X_VECMTX_RESULT_3 (*(const REGType32v *)0x400068c)
+#define reg_G3X_VECMTX_RESULT_4 (*(const REGType32v *)0x4000690)
+#define reg_G3X_VECMTX_RESULT_5 (*(const REGType32v *)0x4000694)
+#define reg_G3X_VECMTX_RESULT_6 (*(const REGType32v *)0x4000698)
+#define reg_G3X_VECMTX_RESULT_7 (*(const REGType32v *)0x400069c)
+#define reg_G3X_VECMTX_RESULT_8 (*(const REGType32v *)0x40006a0)
+
+#define reg_MI_MCD1 (*(REGType32v *)0x4100010)
+
+#define REG_PAD_KEYINPUT_L_SHIFT 9
+#define REG_PAD_KEYINPUT_L_SIZE 1
+#define REG_PAD_KEYINPUT_L_MASK 0x0200
+
+#define REG_PAD_KEYINPUT_R_SHIFT 8
+#define REG_PAD_KEYINPUT_R_SIZE 1
+#define REG_PAD_KEYINPUT_R_MASK 0x0100
+
+#define REG_PAD_KEYINPUT_DOWN_SHIFT 7
+#define REG_PAD_KEYINPUT_DOWN_SIZE 1
+#define REG_PAD_KEYINPUT_DOWN_MASK 0x0080
+
+#define REG_PAD_KEYINPUT_UP_SHIFT 6
+#define REG_PAD_KEYINPUT_UP_SIZE 1
+#define REG_PAD_KEYINPUT_UP_MASK 0x0040
+
+#define REG_PAD_KEYINPUT_LEFT_SHIFT 5
+#define REG_PAD_KEYINPUT_LEFT_SIZE 1
+#define REG_PAD_KEYINPUT_LEFT_MASK 0x0020
+
+#define REG_PAD_KEYINPUT_RIGHT_SHIFT 4
+#define REG_PAD_KEYINPUT_RIGHT_SIZE 1
+#define REG_PAD_KEYINPUT_RIGHT_MASK 0x0010
+
+#define REG_PAD_KEYINPUT_START_SHIFT 3
+#define REG_PAD_KEYINPUT_START_SIZE 1
+#define REG_PAD_KEYINPUT_START_MASK 0x0008
+
+#define REG_PAD_KEYINPUT_SEL_SHIFT 2
+#define REG_PAD_KEYINPUT_SEL_SIZE 1
+#define REG_PAD_KEYINPUT_SEL_MASK 0x0004
+
+#define REG_PAD_KEYINPUT_B_SHIFT 1
+#define REG_PAD_KEYINPUT_B_SIZE 1
+#define REG_PAD_KEYINPUT_B_MASK 0x0002
+
+#define REG_PAD_KEYINPUT_A_SHIFT 0
+#define REG_PAD_KEYINPUT_A_SIZE 1
+#define REG_PAD_KEYINPUT_A_MASK 0x0001
+
+#ifndef SDK_ASM
+#define REG_PAD_KEYINPUT_FIELD( l, r, down, up, left, right, start, sel, b, a ) \
+ (u16)( \
+ ((u32)(l) << REG_PAD_KEYINPUT_L_SHIFT) | \
+ ((u32)(r) << REG_PAD_KEYINPUT_R_SHIFT) | \
+ ((u32)(down) << REG_PAD_KEYINPUT_DOWN_SHIFT) | \
+ ((u32)(up) << REG_PAD_KEYINPUT_UP_SHIFT) | \
+ ((u32)(left) << REG_PAD_KEYINPUT_LEFT_SHIFT) | \
+ ((u32)(right) << REG_PAD_KEYINPUT_RIGHT_SHIFT) | \
+ ((u32)(start) << REG_PAD_KEYINPUT_START_SHIFT) | \
+ ((u32)(sel) << REG_PAD_KEYINPUT_SEL_SHIFT) | \
+ ((u32)(b) << REG_PAD_KEYINPUT_B_SHIFT) | \
+ ((u32)(a) << REG_PAD_KEYINPUT_A_SHIFT))
+#endif
+
+#define REG_PAD_KEYCNT_LOGIC_SHIFT 15
+#define REG_PAD_KEYCNT_LOGIC_SIZE 1
+#define REG_PAD_KEYCNT_LOGIC_MASK 0x8000
+
+#define REG_PAD_KEYCNT_INTR_SHIFT 14
+#define REG_PAD_KEYCNT_INTR_SIZE 1
+#define REG_PAD_KEYCNT_INTR_MASK 0x4000
+
+#define REG_PAD_KEYCNT_L_SHIFT 9
+#define REG_PAD_KEYCNT_L_SIZE 1
+#define REG_PAD_KEYCNT_L_MASK 0x0200
+
+#define REG_PAD_KEYCNT_R_SHIFT 8
+#define REG_PAD_KEYCNT_R_SIZE 1
+#define REG_PAD_KEYCNT_R_MASK 0x0100
+
+#define REG_PAD_KEYCNT_DOWN_SHIFT 7
+#define REG_PAD_KEYCNT_DOWN_SIZE 1
+#define REG_PAD_KEYCNT_DOWN_MASK 0x0080
+
+#define REG_PAD_KEYCNT_UP_SHIFT 6
+#define REG_PAD_KEYCNT_UP_SIZE 1
+#define REG_PAD_KEYCNT_UP_MASK 0x0040
+
+#define REG_PAD_KEYCNT_LEFT_SHIFT 5
+#define REG_PAD_KEYCNT_LEFT_SIZE 1
+#define REG_PAD_KEYCNT_LEFT_MASK 0x0020
+
+#define REG_PAD_KEYCNT_RIGHT_SHIFT 4
+#define REG_PAD_KEYCNT_RIGHT_SIZE 1
+#define REG_PAD_KEYCNT_RIGHT_MASK 0x0010
+
+#define REG_PAD_KEYCNT_START_SHIFT 3
+#define REG_PAD_KEYCNT_START_SIZE 1
+#define REG_PAD_KEYCNT_START_MASK 0x0008
+
+#define REG_PAD_KEYCNT_SEL_SHIFT 2
+#define REG_PAD_KEYCNT_SEL_SIZE 1
+#define REG_PAD_KEYCNT_SEL_MASK 0x0004
+
+#define REG_PAD_KEYCNT_B_SHIFT 1
+#define REG_PAD_KEYCNT_B_SIZE 1
+#define REG_PAD_KEYCNT_B_MASK 0x0002
+
+#define REG_PAD_KEYCNT_A_SHIFT 0
+#define REG_PAD_KEYCNT_A_SIZE 1
+#define REG_PAD_KEYCNT_A_MASK 0x0001
+
+#ifndef SDK_ASM
+#define REG_PAD_KEYCNT_FIELD( logic, intr, l, r, down, up, left, right, start, sel, b, a ) \
+ (u16)( \
+ ((u32)(logic) << REG_PAD_KEYCNT_LOGIC_SHIFT) | \
+ ((u32)(intr) << REG_PAD_KEYCNT_INTR_SHIFT) | \
+ ((u32)(l) << REG_PAD_KEYCNT_L_SHIFT) | \
+ ((u32)(r) << REG_PAD_KEYCNT_R_SHIFT) | \
+ ((u32)(down) << REG_PAD_KEYCNT_DOWN_SHIFT) | \
+ ((u32)(up) << REG_PAD_KEYCNT_UP_SHIFT) | \
+ ((u32)(left) << REG_PAD_KEYCNT_LEFT_SHIFT) | \
+ ((u32)(right) << REG_PAD_KEYCNT_RIGHT_SHIFT) | \
+ ((u32)(start) << REG_PAD_KEYCNT_START_SHIFT) | \
+ ((u32)(sel) << REG_PAD_KEYCNT_SEL_SHIFT) | \
+ ((u32)(b) << REG_PAD_KEYCNT_B_SHIFT) | \
+ ((u32)(a) << REG_PAD_KEYCNT_A_SHIFT))
+#endif
+
+#endif //POKEDIAMOND_REGISTERS_H
diff --git a/arm9/lib/src/FS_archive.c b/arm9/lib/src/FS_archive.c
new file mode 100644
index 00000000..6c0f01f1
--- /dev/null
+++ b/arm9/lib/src/FS_archive.c
@@ -0,0 +1,445 @@
+#include "FS_archive.h"
+#include "FS_file.h"
+#include "FS_command.h"
+#include "FSi_util.h"
+#include "MI_memory.h"
+#include "MI_byteAccess.h"
+#include "OS_printf.h"
+
+FSArchive * arc_list = NULL;
+FSDirPos current_dir_pos;
+
+ARM_FUNC u32 FSi_GetPackedName(const char * name, int name_len)
+{
+ u32 ret = 0;
+ if (name_len <= FS_ARCHIVE_NAME_LEN_MAX)
+ {
+ int i = 0;
+ for (; i < name_len; i++)
+ {
+ u32 c = MI_ReadByte(name + i);
+ if (!c)
+ break;
+ c = (u32)(c - 'A');
+ if (c <= (u32)('Z' - 'A'))
+ c = (u32)(c + 'a');
+ else
+ c = (u32)(c + 'A');
+ ret |= (u32)(c << (i * 8));
+ }
+ }
+ return ret;
+}
+
+ARM_FUNC FSResult FSi_ReadMemCallback(struct FSArchive * p_arc, void * dest, u32 pos, u32 size)
+{
+ MI_CpuCopy8((const void *)FS_GetArchiveOffset(p_arc, pos), dest, size);
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSResult FSi_WriteMemCallback(struct FSArchive * p_arc, const void * src, u32 pos, u32 size)
+{
+ MI_CpuCopy8(src, (void *)FS_GetArchiveOffset(p_arc, pos), size);
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSResult FSi_ReadMemoryCore(FSArchive * p_arc, void * dest, u32 pos, u32 size)
+{
+ MI_CpuCopy8((const void *)pos, dest, size);
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSFile * FSi_NextCommand(FSArchive * p_arc)
+{
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ if (FSi_IsArchiveCanceling(p_arc))
+ {
+ FSFile *p, *q;
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_CANCELING;
+ for (p = p_arc->list.next; p; p = q)
+ {
+ q = p->link.next;
+ if (FS_IsCanceling(p))
+ {
+ if (p_arc->list.next == p)
+ p_arc->list.next = q;
+ FSi_ReleaseCommand(p, FS_RESULT_CANCELED);
+ if (!q)
+ q = p_arc->list.next;
+ }
+ }
+ }
+ if (!FSi_IsArchiveSuspending(p_arc) && !FS_IsArchiveSuspended(p_arc))
+ {
+ FSFile * p_file = p_arc->list.next;
+ if (p_file != NULL)
+ {
+ const BOOL is_start = !FSi_IsArchiveRunning(p_arc);
+ if (is_start)
+ p_arc->flag |= FS_ARCHIVE_FLAG_RUNNING;
+ OS_RestoreInterrupts(bak_psr);
+ if (is_start)
+ {
+ if ((p_arc->proc_flag & FS_ARCHIVE_PROC_ACTIVATE) != 0)
+ (*p_arc->proc) (p_file, FS_COMMAND_ACTIVATE);
+ }
+ bak_psr = OS_DisableInterrupts();
+ p_file->stat |= FS_FILE_STATUS_OPERATING;
+ if (FS_IsFileSyncMode(p_file))
+ {
+ OS_WakeupThread(p_file->queue);
+ OS_RestoreInterrupts(bak_psr);
+ return NULL;
+ }
+ OS_RestoreInterrupts(bak_psr);
+ return p_file;
+ }
+ }
+ if (FSi_IsArchiveRunning(p_arc))
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_RUNNING;
+ if (p_arc->proc_flag & FS_ARCHIVE_PROC_IDLE)
+ {
+ FSFile tmp;
+ FS_InitFile(&tmp);
+ tmp.arc = p_arc;
+ (*p_arc->proc)(&tmp, FS_COMMAND_IDLE);
+ }
+ }
+ if (FSi_IsArchiveSuspending(p_arc))
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_SUSPENDING;
+ p_arc->flag |= FS_ARCHIVE_FLAG_SUSPEND;
+ OS_WakeupThread(&p_arc->stat_q);
+ }
+ OS_RestoreInterrupts(bak_psr);
+ return NULL;
+}
+
+ARM_FUNC void FSi_ExecuteAsyncCommand(FSFile * p_file)
+{
+ FSArchive *const p_arc = p_file->arc;
+ while (p_file)
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ p_file->stat |= FS_FILE_STATUS_OPERATING;
+ if (FS_IsFileSyncMode(p_file))
+ {
+ OS_WakeupThread(p_file->queue);
+ OS_RestoreInterrupts(bak_psr);
+ break;
+ }
+ p_file->stat |= FS_FILE_STATUS_ASYNC;
+ OS_RestoreInterrupts(bak_psr);
+ if (FSi_TranslateCommand(p_file, p_file->command) == FS_RESULT_PROC_ASYNC)
+ break;
+ p_file = FSi_NextCommand(p_arc);
+ }
+}
+
+ARM_FUNC BOOL FSi_ExecuteSyncCommand(FSFile * p_file)
+{
+ FSFile * p_target;
+ FSResult ret = FSi_TranslateCommand(p_file, p_file->command);
+ FSi_ReleaseCommand(p_file, ret);
+ p_target = FSi_NextCommand(p_file->arc);
+ if (p_target)
+ FSi_ExecuteAsyncCommand(p_target);
+ return FS_IsSucceeded(p_file);
+}
+
+ARM_FUNC BOOL FSi_SendCommand(FSFile * p_file, FSCommandType command)
+{
+ FSArchive * p_arc = p_file->arc;
+ const int bit = 1 << command;
+ p_file->command = command;
+ p_file->error = FS_RESULT_BUSY;
+ p_file->stat |= FS_FILE_STATUS_BUSY;
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ if (FSi_IsArchiveUnloading(p_arc))
+ {
+ FSi_ReleaseCommand(p_file, FS_RESULT_CANCELLED);
+ OS_RestoreInterrupts(bak_psr);
+ return FALSE;
+ }
+ if ((bit & FS_ARCHIVE_PROC_SYNC) != 0)
+ p_file->stat |= FS_FILE_STATUS_SYNC;
+ FSi_AppendToList(p_file, (FSFile *)&p_arc->list);
+ if (!FS_IsArchiveSuspended(p_arc) && !FSi_IsArchiveRunning(p_arc))
+ {
+ p_arc->flag |= FS_ARCHIVE_FLAG_RUNNING;
+ OS_RestoreInterrupts(bak_psr);
+ if ((p_arc->proc_flag & FS_ARCHIVE_PROC_ACTIVATE))
+ (*p_arc->proc)(p_file, FS_COMMAND_ACTIVATE);
+ bak_psr = OS_DisableInterrupts();
+ p_file->stat |= FS_FILE_STATUS_OPERATING;
+ if (!FS_IsFileSyncMode(p_file))
+ {
+ OS_RestoreInterrupts(bak_psr);
+ FSi_ExecuteAsyncCommand(p_file);
+ return TRUE;
+ }
+ OS_RestoreInterrupts(bak_psr);
+ }
+ else if (!FS_IsFileSyncMode(p_file))
+ {
+ OS_RestoreInterrupts(bak_psr);
+ return TRUE;
+ }
+ else
+ {
+ do
+ {
+ OS_SleepThread(p_file->queue);
+ } while (!(p_file->stat & FS_FILE_STATUS_OPERATING));
+ OS_RestoreInterrupts(bak_psr);
+ }
+ }
+ return FSi_ExecuteSyncCommand(p_file);
+}
+
+ARM_FUNC void FS_InitArchive(FSArchive * p_arc)
+{
+ MI_CpuClear8(p_arc, sizeof(FSArchive));
+ p_arc->sync_q.head = p_arc->sync_q.tail = NULL;
+ p_arc->stat_q.head = p_arc->stat_q.tail = NULL;
+}
+
+ARM_FUNC FSArchive * const FS_FindArchive(const char * name, int name_len)
+{
+ u32 pack = FSi_GetPackedName(name, name_len);
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ FSArchive * p_arc = arc_list;
+ while (p_arc && (p_arc->name.pack != pack))
+ p_arc = p_arc->next;
+ OS_RestoreInterrupts(bak_psr);
+ return p_arc;
+}
+
+ARM_FUNC BOOL FS_RegisterArchiveName(FSArchive * p_arc, const char * name, int name_len)
+{
+ BOOL ret = FALSE;
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ if (!FS_FindArchive(name, name_len))
+ {
+ FSArchive * p_tail = arc_list;
+ if (!p_tail)
+ {
+ arc_list = p_arc;
+ current_dir_pos.arc = p_arc;
+ current_dir_pos.pos = 0;
+ current_dir_pos.index = 0;
+ current_dir_pos.own_id = 0;
+ }
+ else
+ {
+ while (p_tail->next)
+ p_tail = p_tail->next;
+ p_tail->next = p_arc;
+ p_arc->prev = p_tail;
+ }
+ p_arc->name.pack = FSi_GetPackedName(name, name_len);
+ p_arc->flag |= FS_ARCHIVE_FLAG_REGISTER;
+ ret = TRUE;
+ }
+ OS_RestoreInterrupts(bak_psr);
+ return ret;
+}
+
+ARM_FUNC void FS_ReleaseArchiveName(FSArchive * p_arc)
+{
+ if (p_arc->name.pack)
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ if (p_arc->next)
+ p_arc->next->prev = p_arc->prev;
+ if (p_arc->prev)
+ p_arc->prev->next = p_arc->next;
+ p_arc->name.pack = 0;
+ p_arc->next = p_arc->prev = NULL;
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_REGISTER;
+ if (current_dir_pos.arc == p_arc)
+ {
+ current_dir_pos.arc = arc_list;
+ current_dir_pos.pos = 0;
+ current_dir_pos.index = 0;
+ current_dir_pos.own_id = 0;
+ }
+ OS_RestoreInterrupts(bak_psr);
+ }
+}
+
+ARM_FUNC BOOL FS_LoadArchive(FSArchive * p_arc, u32 base, u32 fat, u32 fat_size, u32 fnt, u32 fnt_size, FS_ARCHIVE_READ_FUNC read_func, FS_ARCHIVE_WRITE_FUNC write_func)
+{
+ p_arc->base = base;
+ p_arc->fat_size = fat_size;
+ p_arc->fat = p_arc->fat_bak = fat;
+ p_arc->fnt_size = fnt_size;
+ p_arc->fnt = p_arc->fnt_bak = fnt;
+ p_arc->read_func = (read_func != NULL) ? read_func : FSi_ReadMemCallback;
+ p_arc->write_func = (write_func != NULL) ? write_func : FSi_WriteMemCallback;
+ p_arc->table_func = p_arc->read_func;
+ p_arc->load_mem = NULL;
+ p_arc->flag |= FS_ARCHIVE_FLAG_LOADED;
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_UnloadArchive(FSArchive * p_arc)
+{
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ if (FS_IsArchiveLoaded(p_arc))
+ {
+ if (FS_IsArchiveTableLoaded(p_arc))
+ {
+ OS_TWarning("memory may leak. preloaded-table of archive \"%s\" (0x%08X)", p_arc->name.ptr, p_arc->load_mem);
+ }
+ {
+ FSFile *p, *q;
+ BOOL bak_state = FS_SuspendArchive(p_arc);
+ p_arc->flag |= FS_ARCHIVE_FLAG_UNLOADING;
+ for (p = p_arc->list.next; p; p = q)
+ {
+ q = p->link.next;
+ FSi_ReleaseCommand(p, FS_RESULT_CANCELED);
+ }
+ p_arc->list.next = NULL;
+ if (bak_state)
+ FS_ResumeArchive(p_arc);
+ }
+ p_arc->base = 0;
+ p_arc->fat = 0;
+ p_arc->fat_size = 0;
+ p_arc->fnt = 0;
+ p_arc->fnt_size = 0;
+ p_arc->fat_bak = p_arc->fnt_bak = 0;
+ p_arc->flag &= ~(FS_ARCHIVE_FLAG_CANCELING | FS_ARCHIVE_FLAG_LOADED | FS_ARCHIVE_FLAG_UNLOADING);
+ }
+ OS_RestoreInterrupts(bak_psr);
+ return TRUE;
+}
+
+ARM_FUNC u32 FS_LoadArchiveTables(FSArchive *p_arc, void *p_mem, u32 max_size)
+{
+ u32 total_size = ALIGN_BYTE(p_arc->fat_size + p_arc->fnt_size + 32, 32);
+ if (total_size <= max_size)
+ {
+ u8 *p_cache = (u8 *)ALIGN_BYTE((u32)p_mem, 32);
+ FSFile tmp;
+ FS_InitFile(&tmp);
+ if (FS_OpenFileDirect(&tmp, p_arc, p_arc->fat, p_arc->fat + p_arc->fat_size, (u32)~0))
+ {
+ if (FS_ReadFile(&tmp, p_cache, (s32)p_arc->fat_size) < 0)
+ {
+ MI_CpuFill8(p_cache, 0x00, p_arc->fat_size);
+ }
+ FS_CloseFile(&tmp);
+ }
+ p_arc->fat = (u32)p_cache;
+ p_cache += p_arc->fat_size;
+ if (FS_OpenFileDirect(&tmp, p_arc, p_arc->fnt, p_arc->fnt + p_arc->fnt_size, (u32)~0))
+ {
+ if (FS_ReadFile(&tmp, p_cache, (s32)p_arc->fnt_size) < 0)
+ {
+ MI_CpuFill8(p_cache, 0x00, p_arc->fnt_size);
+ }
+ FS_CloseFile(&tmp);
+ }
+ p_arc->fnt = (u32)p_cache;
+ p_arc->load_mem = p_mem;
+ p_arc->table_func = FSi_ReadMemoryCore;
+ p_arc->flag |= FS_ARCHIVE_FLAG_TABLE_LOAD;
+ }
+ return total_size;
+}
+
+ARM_FUNC void * FS_UnloadArchiveTables(FSArchive * p_arc)
+{
+ void *ret = NULL;
+ if (FS_IsArchiveLoaded(p_arc))
+ {
+ BOOL bak_stat = FS_SuspendArchive(p_arc);
+ if (FS_IsArchiveTableLoaded(p_arc))
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_TABLE_LOAD;
+ ret = p_arc->load_mem;
+ p_arc->load_mem = NULL;
+ p_arc->fat = p_arc->fat_bak;
+ p_arc->fnt = p_arc->fnt_bak;
+ p_arc->table_func = p_arc->read_func;
+ }
+ if (bak_stat)
+ FS_ResumeArchive(p_arc);
+ }
+ return ret;
+}
+
+ARM_FUNC BOOL FS_SuspendArchive(FSArchive * p_arc)
+{
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ const BOOL bak_stat = !FS_IsArchiveSuspended(p_arc);
+ if (bak_stat)
+ {
+ if (FSi_IsArchiveRunning(p_arc))
+ {
+ p_arc->flag |= FS_ARCHIVE_FLAG_SUSPENDING;
+ do {
+ OS_SleepThread(&p_arc->stat_q);
+ } while (FSi_IsArchiveSuspending(p_arc));
+ }
+ else
+ {
+ p_arc->flag |= FS_ARCHIVE_FLAG_SUSPEND;
+ }
+ }
+ OS_RestoreInterrupts(bak_psr);
+ return bak_stat;
+}
+
+ARM_FUNC BOOL FS_ResumeArchive(FSArchive * p_arc)
+{
+ FSFile * p_target = NULL;
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ const BOOL bak_stat = !FS_IsArchiveSuspended(p_arc);
+ if (!bak_stat)
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_SUSPEND;
+ p_target = FSi_NextCommand(p_arc);
+ }
+ OS_RestoreInterrupts(bak_psr);
+ if (p_target)
+ FSi_ExecuteAsyncCommand(p_target);
+ return bak_stat;
+}
+
+ARM_FUNC void FS_SetArchiveProc(struct FSArchive * p_arc, FS_ARCHIVE_PROC_FUNC proc, u32 flags)
+{
+ if (!flags)
+ proc = NULL;
+ else if (!proc)
+ flags = 0;
+ p_arc->proc = proc;
+ p_arc->proc_flag = flags;
+}
+
+ARM_FUNC void FS_NotifyArchiveAsyncEnd(FSArchive *p_arc, FSResult ret)
+{
+ if (FSi_IsArchiveAsync(p_arc))
+ {
+ FSFile *p_file = p_arc->list.next;
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_ASYNC;
+ FSi_ReleaseCommand(p_file, ret);
+ p_file = FSi_NextCommand(p_arc);
+ if (p_file)
+ FSi_ExecuteAsyncCommand(p_file);
+ }
+ else
+ {
+ FSFile *p_file = p_arc->list.next;
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ p_file->error = ret;
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC;
+ OS_WakeupThread(&p_arc->sync_q);
+ (void)OS_RestoreInterrupts(bak_psr);
+ }
+}
diff --git a/arm9/lib/src/FS_command.c b/arm9/lib/src/FS_command.c
new file mode 100644
index 00000000..818a65ea
--- /dev/null
+++ b/arm9/lib/src/FS_command.c
@@ -0,0 +1,75 @@
+#include "FS_file.h"
+#include "FS_archive.h"
+#include "FSi_util.h"
+#include "FS_command.h"
+
+ARM_FUNC void FSi_ReleaseCommand(FSFile * p_file, FSResult ret)
+{
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ FSi_CutFromList(p_file);
+ p_file->stat &= ~(FS_FILE_STATUS_CANCEL | FS_FILE_STATUS_BUSY | FS_FILE_STATUS_SYNC | FS_FILE_STATUS_ASYNC | FS_FILE_STATUS_OPERATING);
+ p_file->error = ret;
+ OS_WakeupThread(p_file->queue);
+ OS_RestoreInterrupts(bak_psr);
+}
+
+ARM_FUNC FSResult FSi_TranslateCommand(FSFile *p_file, FSCommandType command)
+{
+ FSResult ret;
+
+ FSArchive *const p_arc = p_file->arc;
+ const int bit = (1 << command);
+
+ if (FS_IsFileSyncMode(p_file))
+ p_arc->flag |= FS_ARCHIVE_FLAG_IS_SYNC;
+ else
+ p_arc->flag |= FS_ARCHIVE_FLAG_IS_ASYNC;
+
+ if ((p_arc->proc_flag & bit) != 0)
+ {
+ switch (ret = (*p_arc->proc) (p_file, command))
+ {
+ case FS_RESULT_SUCCESS:
+ case FS_RESULT_FAILURE:
+ case FS_RESULT_UNSUPPORTED:
+ p_file->error = ret;
+ break;
+ case FS_RESULT_PROC_ASYNC:
+ break;
+ case FS_RESULT_PROC_UNKNOWN:
+ ret = FS_RESULT_PROC_DEFAULT;
+ p_arc->proc_flag &= ~bit;
+ break;
+ }
+ }
+ else
+ {
+ ret = FS_RESULT_PROC_DEFAULT;
+ }
+ if (ret == FS_RESULT_PROC_DEFAULT)
+ {
+ ret = (*fsi_default_command[command]) (p_file);
+ }
+ if (ret == FS_RESULT_PROC_ASYNC)
+ {
+ if (FS_IsFileSyncMode(p_file))
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ while (FSi_IsArchiveSync(p_arc))
+ OS_SleepThread(&p_arc->sync_q);
+ ret = p_file->error;
+ OS_RestoreInterrupts(bak_psr);
+ }
+ }
+ else if (!FS_IsFileSyncMode(p_file))
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_ASYNC;
+ FSi_ReleaseCommand(p_file, ret);
+ }
+ else
+ {
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC;
+ p_file->error = ret;
+ }
+ return ret;
+}
diff --git a/arm9/lib/src/FS_command_default.c b/arm9/lib/src/FS_command_default.c
new file mode 100644
index 00000000..002e1d53
--- /dev/null
+++ b/arm9/lib/src/FS_command_default.c
@@ -0,0 +1,468 @@
+#include "nitro.h"
+#include "FS_file.h"
+#include "FS_command.h"
+#include "FS_archive.h"
+#include "MI_byteAccess.h"
+#include "MI_memory.h"
+#include "FSi_util.h"
+
+typedef struct
+{
+ FSArchive *arc;
+ u32 pos;
+}
+FSiSyncReadParam;
+
+ARM_FUNC FSResult FSi_ReadFileCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_WriteFileCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_SeekDirCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_ReadDirCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_FindPathCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_GetPathCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_OpenFileFastCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_OpenFileDirectCommand(FSFile * p_file);
+ARM_FUNC FSResult FSi_CloseFileCommand(FSFile * p_file);
+
+FSResult (*const fsi_default_command[])(FSFile *) = {
+ [FS_COMMAND_READFILE] = FSi_ReadFileCommand,
+ [FS_COMMAND_WRITEFILE] = FSi_WriteFileCommand,
+ [FS_COMMAND_SEEKDIR] = FSi_SeekDirCommand,
+ [FS_COMMAND_READDIR] = FSi_ReadDirCommand,
+ [FS_COMMAND_FINDPATH] = FSi_FindPathCommand,
+ [FS_COMMAND_GETPATH] = FSi_GetPathCommand,
+ [FS_COMMAND_OPENFILEFAST] = FSi_OpenFileFastCommand,
+ [FS_COMMAND_OPENFILEDIRECT] = FSi_OpenFileDirectCommand,
+ [FS_COMMAND_CLOSEFILE] = FSi_CloseFileCommand,
+};
+
+// Case-insensitive string comparison
+ARM_FUNC u32 FSi_StrNICmp(const char * str1, const char * str2, u32 len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ {
+ u32 c = MI_ReadByte(str1 + i) - 'A';
+ u32 d = MI_ReadByte(str2 + i) - 'A';
+ if (c <= 'Z' - 'A')
+ c += 'a' - 'A';
+ if (d <= 'Z' - 'A')
+ d += 'a' - 'A';
+ if (c != d)
+ return c - d;
+ }
+ return 0;
+}
+
+ARM_FUNC FSResult FSi_ReadTable(FSiSyncReadParam * p, void * dst, u32 len)
+{
+ FSResult ret;
+ FSArchive * const p_arc = p->arc;
+ p_arc->flag |= FS_ARCHIVE_FLAG_IS_SYNC;
+ switch (ret = (*p_arc->table_func)(p_arc, dst, p->pos, len))
+ {
+ case FS_RESULT_SUCCESS:
+ case FS_RESULT_FAILURE:
+ p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC;
+ break;
+ case FS_RESULT_PROC_ASYNC:
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ while (FSi_IsArchiveSync(p_arc))
+ OS_SleepThread(&p_arc->sync_q);
+ OS_RestoreInterrupts(bak_psr);
+ ret = p_arc->list.next->error;
+ }
+ break;
+ }
+ p->pos += len;
+ return ret;
+}
+
+ARM_FUNC FSResult FSi_SeekDirDirect(FSFile * p_dir, u32 id)
+{
+ p_dir->stat |= FS_FILE_STATUS_SYNC;
+ p_dir->arg.seekdir.pos.arc = p_dir->arc;
+ p_dir->arg.seekdir.pos.pos = 0;
+ p_dir->arg.seekdir.pos.index = 0;
+ p_dir->arg.seekdir.pos.own_id = (u16)id;
+ return FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR);
+}
+
+// The actual commands
+ARM_FUNC FSResult FSi_ReadFileCommand(FSFile * p_file)
+{
+ FSArchive *const p_arc = p_file->arc;
+ const u32 pos = p_file->prop.file.pos;
+ const u32 len = p_file->arg.readfile.len;
+ void *const dst = p_file->arg.readfile.dst;
+ p_file->prop.file.pos += len;
+ return (*p_arc->read_func)(p_arc, dst, pos, len);
+}
+
+ARM_FUNC FSResult FSi_WriteFileCommand(FSFile * p_file)
+{
+ FSArchive *const p_arc = p_file->arc;
+ const u32 pos = p_file->prop.file.pos;
+ const u32 len = p_file->arg.writefile.len;
+ const void *const src = p_file->arg.writefile.src;
+ p_file->prop.file.pos += len;
+ return (*p_arc->write_func)(p_arc, src, pos, len);
+}
+
+ARM_FUNC FSResult FSi_SeekDirCommand(FSFile * p_dir)
+{
+ FSResult ret;
+ FSArchive *const p_arc = p_dir->arc;
+ const FSDirPos *const arg = &p_dir->arg.seekdir.pos;
+
+ FSArchiveFNT fnt_entry;
+ FSiSyncReadParam param;
+ param.arc = p_arc;
+ param.pos = p_arc->fnt + arg->own_id * sizeof(fnt_entry);
+ ret = FSi_ReadTable(&param, &fnt_entry, sizeof(fnt_entry));
+ if (ret == FS_RESULT_SUCCESS)
+ {
+ p_dir->prop.dir.pos = *arg;
+ if ((arg->index == 0) && (arg->pos == 0))
+ {
+ p_dir->prop.dir.pos.index = fnt_entry.index;
+ p_dir->prop.dir.pos.pos = p_arc->fnt + fnt_entry.start;
+ }
+ p_dir->prop.dir.parent = (u32) (fnt_entry.parent & BIT_MASK(12));
+ }
+ return ret;
+}
+
+ARM_FUNC FSResult FSi_ReadDirCommand(FSFile *p_dir)
+{
+ FSDirEntry *p_entry = p_dir->arg.readdir.p_entry;
+ FSResult ret;
+
+ FSiSyncReadParam param;
+ param.arc = p_dir->arc;
+ param.pos = p_dir->prop.dir.pos.pos;
+
+ {
+ u8 len;
+ ret = FSi_ReadTable(&param, &len, sizeof(len));
+ if (ret != FS_RESULT_SUCCESS)
+ return ret;
+ p_entry->name_len = (u32)(len & BIT_MASK(7));
+ p_entry->is_directory = (u32)((len >> 7) & 1);
+ }
+ if (p_entry->name_len == 0)
+ return FS_RESULT_FAILURE;
+
+ if (!p_dir->arg.readdir.skip_string)
+ {
+ ret = FSi_ReadTable(&param, p_entry->name, p_entry->name_len);
+ if (ret != FS_RESULT_SUCCESS)
+ return ret;
+ MI_WriteByte((u8 *)p_entry->name + p_entry->name_len, (u8)'\0');
+ }
+ else
+ {
+ param.pos += p_entry->name_len;
+ }
+
+ if (p_entry->is_directory)
+ {
+ u16 id;
+ ret = FSi_ReadTable(&param, &id, sizeof(id));
+ if (ret != FS_RESULT_SUCCESS)
+ return ret;
+ p_entry->dir_id.arc = p_dir->arc;
+ p_entry->dir_id.own_id = (u16)(id & BIT_MASK(12));
+ p_entry->dir_id.index = 0;
+ p_entry->dir_id.pos = 0;
+ }
+ else
+ {
+ p_entry->file_id.arc = p_dir->arc;
+ p_entry->file_id.file_id = p_dir->prop.dir.pos.index;
+ ++p_dir->prop.dir.pos.index;
+ }
+ p_dir->prop.dir.pos.pos = param.pos;
+
+ return ret;
+}
+
+ARM_FUNC FSResult FSi_FindPathCommand(FSFile *p_dir)
+{
+ const char *path = p_dir->arg.findpath.path;
+ const BOOL is_dir = p_dir->arg.findpath.find_directory;
+ p_dir->arg.seekdir.pos = p_dir->arg.findpath.pos;
+ (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR);
+ for (; MI_ReadByte(path); path += (MI_ReadByte(path) ? 1 : 0))
+ {
+ u32 is_directory;
+ int name_len = 0;
+ while ((is_directory = MI_ReadByte(path + name_len)),
+ (is_directory && !FSi_IsSlash(is_directory)))
+ ++name_len;
+ if (is_directory || is_dir)
+ is_directory = 1;
+ if (name_len == 0)
+ {
+ return FS_RESULT_FAILURE;
+ }
+ else if (MI_ReadByte(path) == '.')
+ {
+ if (name_len == 1)
+ {
+ path += 1;
+ continue;
+ }
+ else if ((name_len == 2) & (MI_ReadByte(path + 1) == '.'))
+ {
+ if (p_dir->prop.dir.pos.own_id != 0)
+ FSi_SeekDirDirect(p_dir, p_dir->prop.dir.parent);
+ path += 2;
+ continue;
+ }
+ }
+ if (name_len > FS_FILE_NAME_MAX)
+ {
+ return FS_RESULT_FAILURE;
+ }
+ else
+ {
+ FSDirEntry etr;
+ p_dir->arg.readdir.p_entry = &etr;
+ p_dir->arg.readdir.skip_string = FALSE;
+ for (;;)
+ {
+ if (FSi_TranslateCommand(p_dir, FS_COMMAND_READDIR) != FS_RESULT_SUCCESS)
+ return FS_RESULT_FAILURE;
+ if ((is_directory != etr.is_directory) ||
+ (name_len != etr.name_len) || FSi_StrNICmp(path, etr.name, (u32)name_len))
+ continue;
+ if (is_directory)
+ {
+ path += name_len;
+ p_dir->arg.seekdir.pos = etr.dir_id;
+ (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR);
+ break;
+ }
+ else if (is_dir)
+ {
+ return FS_RESULT_FAILURE;
+ }
+ else
+ {
+ *p_dir->arg.findpath.result.file = etr.file_id;
+ return FS_RESULT_SUCCESS;
+ }
+ }
+ }
+ }
+ if (!is_dir)
+ return FS_RESULT_FAILURE;
+ *p_dir->arg.findpath.result.dir = p_dir->prop.dir.pos;
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSResult FSi_GetPathCommand(FSFile *p_file)
+{
+ FSArchive *const p_arc = p_file->arc;
+
+ FSGetPathInfo *p_info = &p_file->arg.getpath;
+
+ FSDirEntry entry;
+ FSFile tmp;
+ u32 dir_id;
+ u32 file_id;
+ u32 id;
+ u32 len;
+
+ enum
+ { INVALID_ID = 0x10000 };
+
+ FS_InitFile(&tmp);
+ tmp.arc = p_file->arc;
+
+ if (FS_IsDir(p_file))
+ {
+ dir_id = p_file->prop.dir.pos.own_id;
+ file_id = INVALID_ID;
+ }
+ else
+ {
+ file_id = p_file->prop.file.own_id;
+ if (p_info->total_len != 0)
+ {
+ dir_id = p_info->dir_id;
+ }
+ else
+ {
+ u32 pos = 0;
+ u32 num_dir = 0;
+ dir_id = INVALID_ID;
+ do
+ {
+ FSi_SeekDirDirect(&tmp, pos);
+ if (!pos)
+ num_dir = tmp.prop.dir.parent;
+ tmp.arg.readdir.p_entry = &entry;
+ tmp.arg.readdir.skip_string = TRUE;
+ while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS)
+ {
+ if (!entry.is_directory && (entry.file_id.file_id == file_id))
+ {
+ dir_id = tmp.prop.dir.pos.own_id;
+ break;
+ }
+ }
+ }
+ while ((dir_id == INVALID_ID) && (++pos < num_dir));
+ }
+ }
+ if (dir_id == INVALID_ID)
+ {
+ p_info->total_len = 0;
+ return FS_RESULT_FAILURE;
+ }
+ if (p_info->total_len == 0)
+ {
+ len = 0;
+ if (p_arc->name.pack <= 0x000000FF)
+ len += 1;
+ else if (p_arc->name.pack <= 0x0000FF00)
+ len += 2;
+ else
+ len += 3;
+ len += 1 + 1;
+ if (file_id != INVALID_ID)
+ len += entry.name_len;
+ id = dir_id;
+ if (id != 0)
+ {
+ FSi_SeekDirDirect(&tmp, id);
+ do
+ {
+ FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent);
+ tmp.arg.readdir.p_entry = &entry;
+ tmp.arg.readdir.skip_string = TRUE;
+ while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS)
+ {
+ if (entry.is_directory && (entry.dir_id.own_id == id))
+ {
+ len += entry.name_len + 1;
+ break;
+ }
+ }
+ id = tmp.prop.dir.pos.own_id;
+ }
+ while (id != 0);
+ }
+ p_info->total_len = (u16)(len + 1);
+ p_info->dir_id = (u16)dir_id;
+ }
+ if (!p_info->buf)
+ return FS_RESULT_SUCCESS;
+ if (p_info->buf_len < p_info->total_len)
+ return FS_RESULT_FAILURE;
+ else
+ {
+ u8 *dst = p_info->buf;
+ u32 total = p_info->total_len;
+ u32 pos = 0;
+ if (p_arc->name.pack <= 0x000000FF)
+ len = 1;
+ else if (p_arc->name.pack <= 0x0000FF00)
+ len = 2;
+ else
+ len = 3;
+ MI_CpuCopy8(p_arc->name.ptr, dst + pos, len);
+ pos += len;
+ MI_CpuCopy8(":/", dst + pos, 2);
+ pos += 2;
+ id = dir_id;
+ FSi_SeekDirDirect(&tmp, id);
+ if (file_id != INVALID_ID)
+ {
+ tmp.arg.readdir.p_entry = &entry;
+ tmp.arg.readdir.skip_string = FALSE;
+ while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS)
+ {
+ if (!entry.is_directory && (entry.file_id.file_id == file_id))
+ break;
+ }
+ len = entry.name_len + 1;
+ MI_CpuCopy8(entry.name, dst + total - len, len);
+ total -= len;
+ }
+ else
+ {
+ MI_WriteByte(dst + total - 1, '\0');
+ total -= 1;
+ }
+ if (id != 0)
+ {
+ do
+ {
+ FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent);
+ tmp.arg.readdir.p_entry = &entry;
+ tmp.arg.readdir.skip_string = FALSE;
+ MI_WriteByte(dst + total - 1, '/');
+ total -= 1;
+ while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS)
+ {
+ if (entry.is_directory && (entry.dir_id.own_id == id))
+ {
+ len = entry.name_len;
+ MI_CpuCopy8(entry.name, dst + total - len, len);
+ total -= len;
+ break;
+ }
+ }
+ id = tmp.prop.dir.pos.own_id;
+ }
+ while (id != 0);
+ }
+ }
+
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSResult FSi_OpenFileFastCommand(FSFile * p_file)
+{
+ FSArchive *const p_arc = p_file->arc;
+ const FSFileID *p_id = &p_file->arg.openfilefast.id;
+ const u32 index = p_id->file_id;
+ FSResult ret;
+
+ {
+ u32 pos = (u32)(index * sizeof(FSArchiveFAT));
+ if (pos >= p_arc->fat_size)
+ return FS_RESULT_FAILURE;
+ else
+ {
+ FSArchiveFAT fat;
+ FSiSyncReadParam param;
+ param.arc = p_arc;
+ param.pos = p_arc->fat + pos;
+ ret = FSi_ReadTable(&param, &fat, sizeof(fat));
+ if (ret != FS_RESULT_SUCCESS)
+ return ret;
+ p_file->arg.openfiledirect.top = fat.top;
+ p_file->arg.openfiledirect.bottom = fat.bottom;
+ p_file->arg.openfiledirect.index = index;
+ return FSi_TranslateCommand(p_file, FS_COMMAND_OPENFILEDIRECT);
+ }
+ }
+}
+
+ARM_FUNC FSResult FSi_OpenFileDirectCommand(FSFile * p_file)
+{
+ p_file->prop.file.top = p_file->arg.openfiledirect.top;
+ p_file->prop.file.pos = p_file->arg.openfiledirect.top;
+ p_file->prop.file.bottom = p_file->arg.openfiledirect.bottom;
+ p_file->prop.file.own_id = p_file->arg.openfiledirect.index;
+ return FS_RESULT_SUCCESS;
+}
+
+ARM_FUNC FSResult FSi_CloseFileCommand(FSFile * p_file)
+{
+ return FS_RESULT_SUCCESS;
+}
diff --git a/arm9/lib/src/FS_file.c b/arm9/lib/src/FS_file.c
new file mode 100644
index 00000000..8bca5c8e
--- /dev/null
+++ b/arm9/lib/src/FS_file.c
@@ -0,0 +1,242 @@
+#include "nitro.h"
+#include "MI_byteAccess.h"
+#include "FS_rom.h"
+#include "FS_file.h"
+#include "FSi_util.h"
+
+extern FSDirPos current_dir_pos;
+BOOL is_init = FALSE;
+
+ARM_FUNC void FS_Init(u32 default_dma_no)
+{
+ if (!is_init)
+ {
+ is_init = TRUE;
+ FSi_InitRom(default_dma_no);
+ }
+}
+
+ARM_FUNC BOOL FS_IsAvailable(void)
+{
+ return is_init;
+}
+
+ARM_FUNC void FS_InitFile(FSFile * p_file)
+{
+ p_file->link.next = p_file->link.prev = NULL;
+ OS_InitThreadQueue(p_file->queue);
+ p_file->arc = NULL;
+ p_file->command = FS_COMMAND_INVALID;
+ p_file->stat = 0;
+}
+
+static BOOL FSi_FindPath(FSFile * p_dir, const char * path, FSFileID * p_file_id, FSDirPos * p_dir_pos)
+{
+ FSDirPos pos;
+ if (FSi_IsSlash(MI_ReadByte(path)))
+ {
+ pos.arc = current_dir_pos.arc;
+ pos.own_id = 0;
+ pos.pos = 0;
+ pos.index = 0;
+ path++;
+ }
+ else
+ {
+ int i;
+ pos = current_dir_pos;
+ for (i = 0; i <= FS_ARCHIVE_NAME_LEN_MAX; ++i)
+ {
+ u32 c = MI_ReadByte(path + i);
+ if (!c || FSi_IsSlash(c))
+ break;
+ else if (c == ':')
+ {
+ FSArchive * const p_arc = FS_FindArchive(path, i);
+ if (!p_arc)
+ {
+ return FALSE;
+ }
+ else if (!FS_IsArchiveLoaded(p_arc))
+ {
+ return FALSE;
+ }
+ pos.arc = p_arc;
+ pos.pos = 0;
+ pos.index = 0;
+ pos.own_id = 0;
+ path += i + 1;
+ if (FSi_IsSlash(MI_ReadByte(path)))
+ ++path;
+ break;
+ }
+ }
+ }
+ p_dir->arc = pos.arc;
+ p_dir->arg.findpath.path = path;
+ p_dir->arg.findpath.pos = pos;
+ if (p_dir_pos)
+ {
+ p_dir->arg.findpath.find_directory = TRUE;
+ p_dir->arg.findpath.result.dir = p_dir_pos;
+ }
+ else
+ {
+ p_dir->arg.findpath.find_directory = FALSE;
+ p_dir->arg.findpath.result.file = p_file_id;
+ }
+ return FSi_SendCommand(p_dir, FS_COMMAND_FINDPATH);
+}
+
+ARM_FUNC int FSi_ReadFileCore(FSFile * p_file, void * dst, s32 len, BOOL async)
+{
+ const s32 pos = p_file->prop.file.pos;
+ const s32 rest = p_file->prop.file.bottom - pos;
+ const u32 org = len;
+ if (len > rest)
+ len = rest;
+ if (len < 0)
+ len = 0;
+ p_file->arg.readfile.dst = dst;
+ p_file->arg.readfile.len_org = org;
+ p_file->arg.readfile.len = len;
+ if (!async)
+ p_file->stat |= FS_FILE_STATUS_SYNC;
+ FSi_SendCommand(p_file, FS_COMMAND_READFILE);
+ if (!async)
+ {
+ if (FS_WaitAsync(p_file))
+ len = p_file->prop.file.pos - pos;
+ else
+ len = -1;
+ }
+ return len;
+}
+
+ARM_FUNC BOOL FS_ConvertPathToFileID(FSFileID * p_file_id, const char * path)
+{
+ FSFile dir;
+ FS_InitFile(&dir);
+ if (!FSi_FindPath(&dir, path, p_file_id, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_OpenFileDirect(FSFile * p_file, FSArchive * p_arc, u32 image_top, u32 image_bottom, u32 file_index)
+{
+ p_file->arc = p_arc;
+ p_file->arg.openfiledirect.index = file_index;
+ p_file->arg.openfiledirect.top = image_top;
+ p_file->arg.openfiledirect.bottom = image_bottom;
+ if (!FSi_SendCommand(p_file, FS_COMMAND_OPENFILEDIRECT))
+ return FALSE;
+ p_file->stat |= FS_FILE_STATUS_IS_FILE;
+ p_file->stat &= ~FS_FILE_STATUS_IS_DIR;
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_OpenFileFast(FSFile * p_file, FSFileID file_id)
+{
+ if (!file_id.arc)
+ return FALSE;
+ p_file->arc = file_id.arc;
+ p_file->arg.openfilefast.id = file_id;
+ if (!FSi_SendCommand(p_file, FS_COMMAND_OPENFILEFAST))
+ return FALSE;
+ p_file->stat |= FS_FILE_STATUS_IS_FILE;
+ p_file->stat &= ~FS_FILE_STATUS_IS_DIR;
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_OpenFile(FSFile * p_file, const char * path)
+{
+ FSFileID file_id;
+ return FS_ConvertPathToFileID(&file_id, path) && FS_OpenFileFast(p_file, file_id);
+}
+
+ARM_FUNC BOOL FS_CloseFile(FSFile * p_file)
+{
+ if (!FSi_SendCommand(p_file, FS_COMMAND_CLOSEFILE))
+ return FALSE;
+ p_file->arc = NULL;
+ p_file->command = FS_COMMAND_INVALID;
+ p_file->stat &= ~(FS_FILE_STATUS_IS_FILE | FS_FILE_STATUS_IS_DIR);
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_WaitAsync(FSFile * p_file)
+{
+ BOOL is_owner = FALSE;
+ OSIntrMode bak_par = OS_DisableInterrupts();
+ if (FS_IsBusy(p_file))
+ {
+ is_owner = !(p_file->stat & (FS_FILE_STATUS_SYNC | FS_FILE_STATUS_OPERATING));
+ if (is_owner)
+ {
+ p_file->stat |= FS_FILE_STATUS_SYNC;
+ do
+ {
+ OS_SleepThread(p_file->queue);
+ } while (!(p_file->stat & FS_FILE_STATUS_OPERATING));
+ }
+ else
+ {
+ do
+ {
+ OS_SleepThread(p_file->queue);
+ } while (FS_IsBusy(p_file));
+ }
+ }
+ (void)OS_RestoreInterrupts(bak_par);
+ if (is_owner)
+ {
+ return FSi_ExecuteSyncCommand(p_file);
+ }
+
+ return FS_IsSucceeded(p_file);
+}
+
+ARM_FUNC int FS_ReadFileAsync(FSFile * p_file, void * dst, s32 len)
+{
+ return FSi_ReadFileCore(p_file, dst, len, TRUE);
+}
+
+ARM_FUNC int FS_ReadFile(FSFile * p_file, void * dst, s32 len)
+{
+ return FSi_ReadFileCore(p_file, dst, len, FALSE);
+}
+
+ARM_FUNC BOOL FS_SeekFile(FSFile * p_file, int offset, FSSeekFileMode origin)
+{
+ switch (origin)
+ {
+ case FS_SEEK_SET:
+ offset += p_file->prop.file.top;
+ break;
+ case FS_SEEK_CUR:
+ offset += p_file->prop.file.pos;
+ break;
+ case FS_SEEK_END:
+ offset += p_file->prop.file.bottom;
+ break;
+ default:
+ return FALSE;
+ }
+ if (offset < (s32)p_file->prop.file.top)
+ offset = (s32)p_file->prop.file.top;
+ if (offset > (s32)p_file->prop.file.bottom)
+ offset = (s32)p_file->prop.file.bottom;
+ p_file->prop.file.pos = offset;
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_ChangeDir(const char * path)
+{
+ FSDirPos pos;
+ FSFile dir;
+ FS_InitFile(&dir);
+ if (!FSi_FindPath(&dir, path, NULL, &pos))
+ return FALSE;
+ current_dir_pos = pos;
+ return TRUE;
+}
diff --git a/arm9/lib/src/FS_overlay.c b/arm9/lib/src/FS_overlay.c
new file mode 100644
index 00000000..79a3b43e
--- /dev/null
+++ b/arm9/lib/src/FS_overlay.c
@@ -0,0 +1,320 @@
+#include "nitro.h"
+#include "DGT_common.h"
+#include "DGT_dgt.h"
+#include "OS_cache.h"
+#include "OS_system.h"
+#include "OS_printf.h"
+#include "MI_memory.h"
+#include "MI_uncompress.h"
+#include "FS_rom.h"
+#include "FS_overlay.h"
+#include "FS_mw_dtor.h"
+#include "MB_mb.h"
+
+#define FS_OVERLAY_FLAG_COMP 0x0001
+#define FS_OVERLAY_FLAG_AUTH 0x0002
+#define FS_OVERLAY_DIGEST_SIZE DGT_HASH2_DIGEST_SIZE
+
+ARM_FUNC u32 FSi_GetOverlayBinarySize(FSOverlayInfo * p_ovi)
+{
+ u32 size = (p_ovi->header.flag & FS_OVERLAY_FLAG_COMP)
+ ? p_ovi->header.compressed
+ : p_ovi->header.ram_size;
+ return size;
+}
+
+ARM_FUNC void FS_ClearOverlayImage(FSOverlayInfo * p_ovi)
+{
+ u8 * const im_start = FS_GetOverlayAddress(p_ovi);
+ u32 const ram_size = FS_GetOverlayImageSize(p_ovi);
+ u32 const total_size = FS_GetOverlayTotalSize(p_ovi);
+
+ IC_InvalidateRange(im_start, total_size);
+ DC_InvalidateRange(im_start, total_size);
+ MI_CpuFill8(im_start + ram_size, 0, total_size - ram_size);
+}
+
+ARM_FUNC FSFileID FS_GetOverlayFileID(FSOverlayInfo * p_ovi)
+{
+ FSFileID ret;
+ ret.arc = &fsi_arc_rom;
+ ret.file_id = p_ovi->header.file_id;
+ return ret;
+}
+
+ARM_FUNC BOOL FSi_LoadOverlayInfoCore(FSOverlayInfo * p_ovi, MIProcessor target, FSOverlayID id, FSArchive * arc, u32 offset_arm9, u32 len_arm9, u32 offset_arm7, u32 len_arm7)
+{
+ CARDRomRegion pr[1];
+ u32 pos;
+ if (target == MI_PROCESSOR_ARM9)
+ {
+ pr->offset = offset_arm9;
+ pr->length = len_arm9;
+ }
+ else
+ {
+ pr->offset = offset_arm7;
+ pr->length = len_arm7;
+ }
+ pos = (u32) id * sizeof(FSOverlayInfoHeader);
+ if (pos >= pr->length)
+ return FALSE;
+
+ FSFile file[1];
+ FS_InitFile(file);
+ // BOOL FS_OpenFileDirect(FSFile * p_file, FSArchive * p_arc, u32 image_top, u32 image_bottom, u32 file_index)
+ if (!FS_OpenFileDirect(file, arc, pr->offset + pos, pr->offset + pr->length, (u32)~0))
+ return FALSE;
+ if (FS_ReadFile(file, p_ovi, sizeof(FSOverlayInfoHeader)) != sizeof(FSOverlayInfoHeader))
+ {
+ FS_CloseFile(file);
+ return FALSE;
+ }
+ FS_CloseFile(file);
+ p_ovi->target = target;
+ if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
+ return FALSE;
+ p_ovi->file_pos.offset = FS_GetFileImageTop(file);
+ p_ovi->file_pos.length = FS_GetLength(file);
+ FS_CloseFile(file);
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_LoadOverlayInfo(FSOverlayInfo * p_ovi, MIProcessor target, FSOverlayID id)
+{
+ CARDRomRegion * const pr = (target == MI_PROCESSOR_ARM9) ? &fsi_ovt9 : &fsi_ovt7;
+ if (pr->offset)
+ {
+ FSFile file[1];
+ const u32 pos = id * sizeof(FSOverlayInfoHeader);
+ if (pos >= pr->length)
+ return FALSE;
+ MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
+ p_ovi->target = target;
+ FS_InitFile(file);
+ if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
+ return FALSE;
+ p_ovi->file_pos.offset = FS_GetFileImageTop(file);
+ p_ovi->file_pos.length = FS_GetLength(file);
+ FS_CloseFile(file);
+ return TRUE;
+ }
+ else
+ {
+ const CARDRomRegion * const p_ovt9 = CARD_GetRomRegionOVT(MI_PROCESSOR_ARM9);
+ const CARDRomRegion * const p_ovt7 = CARD_GetRomRegionOVT(MI_PROCESSOR_ARM7);
+ return FSi_LoadOverlayInfoCore(p_ovi, target, id, &fsi_arc_rom, p_ovt9->offset, p_ovt9->length, p_ovt7->offset, p_ovt7->length);
+ }
+}
+
+ARM_FUNC BOOL FS_LoadOverlayImageAsync(FSOverlayInfo * p_ovi, FSFile * p_file)
+{
+ FS_InitFile(p_file);
+ if (!FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi)))
+ return FALSE;
+ else
+ {
+ s32 size = FSi_GetOverlayBinarySize(p_ovi);
+ FS_ClearOverlayImage(p_ovi);
+ if (FS_ReadFileAsync(p_file, FS_GetOverlayAddress(p_ovi), size) != size)
+ {
+ FS_CloseFile(p_file);
+ return FALSE;
+ }
+ return TRUE;
+ }
+}
+
+ARM_FUNC BOOL FS_LoadOverlayImage(FSOverlayInfo * p_ovi)
+{
+ FSFile file[1];
+ FS_InitFile(file);
+ if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
+ return FALSE;
+ else
+ {
+ s32 size = FSi_GetOverlayBinarySize(p_ovi);
+ FS_ClearOverlayImage(p_ovi);
+ if (FS_ReadFile(file, FS_GetOverlayAddress(p_ovi), size) != size)
+ {
+ FS_CloseFile(file);
+ return FALSE;
+ }
+ FS_CloseFile(file);
+ return TRUE;
+ }
+}
+
+static const u8 fsi_def_digest_key[64] = {
+ 0x21, 0x06, 0xc0, 0xde,
+ 0xba, 0x98, 0xce, 0x3f,
+ 0xa6, 0x92, 0xe3, 0x9d,
+ 0x46, 0xf2, 0xed, 0x01,
+
+ 0x76, 0xe3, 0xcc, 0x08,
+ 0x56, 0x23, 0x63, 0xfa,
+ 0xca, 0xd4, 0xec, 0xdf,
+ 0x9a, 0x62, 0x78, 0x34,
+
+ 0x8f, 0x6d, 0x63, 0x3c,
+ 0xfe, 0x22, 0xca, 0x92,
+ 0x20, 0x88, 0x97, 0x23,
+ 0xd2, 0xcf, 0xae, 0xc2,
+
+ 0x32, 0x67, 0x8d, 0xfe,
+ 0xca, 0x83, 0x64, 0x98,
+ 0xac, 0xfd, 0x3e, 0x37,
+ 0x87, 0x46, 0x58, 0x24,
+};
+
+static const void *fsi_digest_key_ptr = fsi_def_digest_key;
+static int fsi_digest_key_len = sizeof(fsi_def_digest_key);
+
+ARM_FUNC BOOL FSi_CompareDigest(const u8 *spec_digest, void *src, int len)
+{
+ int i;
+ u8 digest[FS_OVERLAY_DIGEST_SIZE];
+ u8 digest_key[64];
+
+ MI_CpuClear8(digest, sizeof(digest));
+ MI_CpuCopy8(fsi_digest_key_ptr, digest_key, fsi_digest_key_len);
+ DGT_Hash2CalcHmac(digest, src, len, digest_key, fsi_digest_key_len);
+ for (i = 0; i < sizeof(digest); i += sizeof(u32))
+ {
+ if (*(const u32 *)(digest + i) != *(const u32 *)(spec_digest + i))
+ break;
+ }
+ return i == sizeof(digest);
+}
+
+extern u8 SDK_OVERLAY_DIGEST[];
+extern u8 SDK_OVERLAY_DIGEST_END[];
+
+ARM_FUNC void FS_StartOverlay(FSOverlayInfo * p_ovi)
+{
+ u32 rare_size = FSi_GetOverlayBinarySize(p_ovi);
+ if (MB_IsMultiBootChild())
+ {
+ BOOL ret = FALSE;
+
+ if (p_ovi->header.flag & FS_OVERLAY_FLAG_AUTH)
+ {
+ const u32 odt_max = (u32)((SDK_OVERLAY_DIGEST_END - SDK_OVERLAY_DIGEST) / FS_OVERLAY_DIGEST_SIZE);
+ if (p_ovi->header.id < odt_max)
+ {
+ const u8 * spec_digest = SDK_OVERLAY_DIGEST + FS_OVERLAY_DIGEST_SIZE * p_ovi->header.id;
+ ret = FSi_CompareDigest(spec_digest, p_ovi->header.ram_address, (int)rare_size);
+ }
+ }
+ if (!ret)
+ {
+ MI_CpuClear8(p_ovi->header.ram_address, rare_size);
+ OS_TPanic("FS_StartOverlay() failed! (invalid overlay-segment data)");
+ return;
+ }
+ }
+ if (p_ovi->header.flag & FS_OVERLAY_FLAG_COMP)
+ {
+ MIi_UncompressBackward(p_ovi->header.ram_address + rare_size);
+ }
+ DC_FlushRange(p_ovi->header.ram_address, p_ovi->header.ram_size);
+
+ {
+ FSOverlayInitFunc *p = p_ovi->header.sinit_init;
+ FSOverlayInitFunc *q = p_ovi->header.sinit_init_end;
+ for (; p < q; ++p)
+ {
+ if (*p)
+ (**p)();
+ }
+ }
+}
+
+ARM_FUNC void FS_EndOverlay(FSOverlayInfo *p_ovi)
+{
+ for (;;)
+ {
+ MWiDestructorChain *head = NULL, *tail = NULL;
+ const u32 region_top = (u32)FS_GetOverlayAddress(p_ovi);
+ const u32 region_bottom = region_top + FS_GetOverlayTotalSize(p_ovi);
+
+ {
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ MWiDestructorChain *prev = NULL;
+ MWiDestructorChain *base = __global_destructor_chain;
+ MWiDestructorChain *p = base;
+ while (p)
+ {
+ MWiDestructorChain *next = p->next;
+ const u32 dtor = (u32)p->dtor;
+ const u32 obj = (u32)p->obj;
+ if (((obj == 0) && (dtor >= region_top) && (dtor < region_bottom)) ||
+ ((obj >= region_top) && (obj < region_bottom)))
+ {
+ /* If appropriate, extract*/
+ if (!tail)
+ {
+ head = p;
+ }
+ else
+ {
+ tail->next = p;
+ }
+ if (base == p)
+ {
+ base = __global_destructor_chain = next;
+ }
+ tail = p, p->next = NULL;
+ if (prev)
+ {
+ prev->next = next;
+ }
+ }
+ else
+ {
+ prev = p;
+ }
+ p = next;
+ }
+ OS_RestoreInterrupts(bak_psr);
+ }
+
+ if (!head)
+ {
+ break;
+ }
+ do
+ {
+ MWiDestructorChain *next = head->next;
+ if (head->dtor)
+ {
+ (*head->dtor) (head->obj);
+ }
+ head = next;
+ }
+ while (head);
+ }
+}
+
+ARM_FUNC BOOL FS_UnloadOverlayImage(FSOverlayInfo * p_ovi)
+{
+ FS_EndOverlay(p_ovi);
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_LoadOverlay(MIProcessor target, FSOverlayID id)
+{
+ FSOverlayInfo ovi;
+ if (!FS_LoadOverlayInfo(&ovi, target, id) || !FS_LoadOverlayImage(&ovi))
+ return FALSE;
+ FS_StartOverlay(&ovi);
+ return TRUE;
+}
+
+ARM_FUNC BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id)
+{
+ FSOverlayInfo ovi;
+ if (!FS_LoadOverlayInfo(&ovi, target, id) || !FS_UnloadOverlayImage(&ovi))
+ return FALSE;
+ return TRUE;
+}
diff --git a/arm9/lib/src/FS_rom.c b/arm9/lib/src/FS_rom.c
new file mode 100644
index 00000000..32f66c10
--- /dev/null
+++ b/arm9/lib/src/FS_rom.c
@@ -0,0 +1,118 @@
+#include "FS_rom.h"
+#include "FS_archive.h"
+#include "FS_file.h"
+#include "CARD_pullOut.h"
+#include "CARD_rom.h"
+#include "CARD_common.h"
+#include "MB_mb.h"
+#include "OS_printf.h"
+
+u32 fsi_default_dma_no;
+
+ARM_FUNC void FSi_OnRomReadDone(void * p_arc)
+{
+ FS_NotifyArchiveAsyncEnd(p_arc, CARD_IsPulledOut() ? FS_RESULT_ERROR : FS_RESULT_SUCCESS);
+}
+
+ARM_FUNC FSResult FSi_ReadRomCallback(FSArchive * p_arc, void * dst, u32 src, u32 len)
+{
+ CARD_ReadRomAsync(fsi_default_dma_no, (const void *)src, dst, len, FSi_OnRomReadDone, p_arc);
+ return FS_RESULT_PROC_ASYNC;
+}
+
+ARM_FUNC FSResult FSi_WriteDummyCallback(FSArchive * p_arc, const void *src, u32 dst, u32 len)
+{
+ return FS_RESULT_FAILURE;
+}
+
+ARM_FUNC FSResult FSi_RomArchiveProc(FSFile * p_arc, FSCommandType cmd)
+{
+ switch (cmd)
+ {
+ case FS_COMMAND_ACTIVATE:
+ CARD_LockRom(fsi_card_lock_id);
+ return FS_RESULT_SUCCESS;
+ case FS_COMMAND_IDLE:
+ CARD_UnlockRom(fsi_card_lock_id);
+ return FS_RESULT_SUCCESS;
+ case FS_COMMAND_WRITEFILE:
+ return FS_RESULT_UNSUPPORTED;
+ default:
+ return FS_RESULT_PROC_UNKNOWN;
+ }
+}
+
+ARM_FUNC FSResult FSi_ReadDummyCallback(FSArchive *p_arc, void *dst, u32 src, u32 len)
+{
+ return FS_RESULT_FAILURE;
+}
+
+ARM_FUNC FSResult FSi_EmptyArchiveProc(FSFile *p_file, FSCommandType cmd)
+{
+ return FS_RESULT_UNSUPPORTED;
+}
+
+ARM_FUNC void FSi_InitRom(u32 default_dma_no)
+{
+ fsi_default_dma_no = default_dma_no;
+ fsi_card_lock_id = OS_GetLockID();
+ fsi_ovt9.offset = 0;
+ fsi_ovt9.length = 0;
+ fsi_ovt7.offset = 0;
+ fsi_ovt7.length = 0;
+
+ CARD_Init();
+
+ FS_InitArchive(&fsi_arc_rom);
+ FS_RegisterArchiveName(&fsi_arc_rom, "rom", 3);
+
+ if (MB_IsMultiBootChild())
+ {
+ fsi_ovt9.offset = (u32)~0;
+ fsi_ovt9.length = 0;
+ fsi_ovt7.offset = (u32)~0;
+ fsi_ovt7.length = 0;
+ FS_SetArchiveProc(&fsi_arc_rom, FSi_EmptyArchiveProc, (u32)FS_ARCHIVE_PROC_ALL);
+ FS_LoadArchive(&fsi_arc_rom, 0x00000000, 0, 0, 0, 0, FSi_ReadDummyCallback, FSi_WriteDummyCallback);
+ }
+ else
+ {
+ const CARDRomRegion *const fnt = CARD_GetRomRegionFNT();
+ const CARDRomRegion *const fat = CARD_GetRomRegionFAT();
+
+ FS_SetArchiveProc(&fsi_arc_rom, FSi_RomArchiveProc,
+ FS_ARCHIVE_PROC_WRITEFILE |
+ FS_ARCHIVE_PROC_ACTIVATE | FS_ARCHIVE_PROC_IDLE);
+
+ if ((fnt->offset == 0xFFFFFFFF) || (fnt->offset == 0x00000000) ||
+ (fat->offset == 0xFFFFFFFF) || (fat->offset == 0x00000000))
+ {
+ OS_Warning("file-system : no MAKEROM-information in rom header.");
+ }
+ else
+ {
+ FS_LoadArchive(&fsi_arc_rom, 0x00000000,
+ fat->offset, fat->length,
+ fnt->offset, fnt->length,
+ FSi_ReadRomCallback, FSi_WriteDummyCallback);
+ }
+ }
+}
+
+ARM_FUNC u32 FS_SetDefaultDMA(u32 dma_no)
+{
+ OSIntrMode bak_psr = OS_DisableInterrupts();
+ u32 bak_dma_no = fsi_default_dma_no;
+ BOOL bak_stat = FS_SuspendArchive(&fsi_arc_rom);
+ fsi_default_dma_no = dma_no;
+ if (bak_stat)
+ FS_ResumeArchive(&fsi_arc_rom);
+ OS_RestoreInterrupts(bak_psr);
+ return bak_dma_no;
+}
+
+ARM_FUNC u32 FS_TryLoadTable(void * p_mem, u32 size)
+{
+ return FS_LoadArchiveTables(&fsi_arc_rom, p_mem, size);
+}
+
diff --git a/arm9/lib/src/FX_cp.c b/arm9/lib/src/FX_cp.c
index 2ca9d720..3b6e6c96 100644
--- a/arm9/lib/src/FX_cp.c
+++ b/arm9/lib/src/FX_cp.c
@@ -16,8 +16,8 @@ ARM_FUNC fx32 FX_Inv(fx32 x){
ARM_FUNC fx32 FX_Sqrt(fx32 x){
if (x > 0)
{
- SETREG16(HW_REG_SQRTCNT, 0x1);
- SETREG64(HW_REG_SQRT_PARAM, (fx64)x << 32);
+ reg_CP_SQRTCNT = 0x1;
+ reg_CP_SQRT_PARAM = (fx64)x << 32;
return FX_GetSqrtResult();
}
else
@@ -27,44 +27,44 @@ ARM_FUNC fx32 FX_Sqrt(fx32 x){
}
ARM_FUNC fx64c FX_GetDivResultFx64c(){
- while (READREG16(HW_REG_DIVCNT) & 0x8000);
- return READREG64(HW_REG_DIV_RESULT);
+ while (reg_CP_DIVCNT & 0x8000);
+ return reg_CP_DIV_RESULT;
}
ARM_FUNC fx32 FX_GetDivResult(){
- while (READREG16(HW_REG_DIVCNT) & 0x8000);
- return (READREG64(HW_REG_DIV_RESULT) + (1 << (0x14 - 1))) >> 0x14;
+ while (reg_CP_DIVCNT & 0x8000);
+ return (reg_CP_DIV_RESULT + (1 << (0x14 - 1))) >> 0x14;
}
ARM_FUNC void FX_InvAsync(fx32 x){
- SETREG16(HW_REG_DIVCNT, 0x1);
- SETREG64(HW_REG_DIV_NUMER, (fx64)0x00001000 << 32);
- SETREG64(HW_REG_DIV_DENOM, (u32)x);
+ reg_CP_DIVCNT = 0x1;
+ reg_CP_DIV_NUMER = (fx64)0x00001000 << 32;
+ reg_CP_DIV_DENOM = (u32)x;
}
ARM_FUNC fx32 FX_GetSqrtResult(){
- while (READREG16(HW_REG_SQRTCNT) & 0x8000);
- return (READREG32(HW_REG_SQRT_RESULT) + (1 << (0xA - 1))) >> 0xA;
+ while (reg_CP_SQRTCNT & 0x8000);
+ return (reg_CP_SQRT_RESULT + (1 << (0xA - 1))) >> 0xA;
}
ARM_FUNC void FX_DivAsync(fx32 numerator, fx32 denominator){
- SETREG16(HW_REG_DIVCNT, 0x1);
- SETREG64(HW_REG_DIV_NUMER, (fx64)numerator << 32);
- SETREG64(HW_REG_DIV_DENOM, (u32)denominator);
+ reg_CP_DIVCNT = 0x1;
+ reg_CP_DIV_NUMER = (fx64)numerator << 32;
+ reg_CP_DIV_DENOM = (u32)denominator;
}
ARM_FUNC fx32 FX_DivS32(fx32 numerator, fx32 denominator){
- SETREG16(HW_REG_DIVCNT, 0x0);
- SETREG32(HW_REG_DIV_NUMER, (u32)numerator); //32bit write for some reason
- SETREG64(HW_REG_DIV_DENOM, (u32)denominator);
- while (READREG16(HW_REG_DIVCNT) & 0x8000);
- return READREG32(HW_REG_DIV_RESULT);
+ reg_CP_DIVCNT = 0x0;
+ *(REGType32v *)&reg_CP_DIV_NUMER = (u32)numerator; //32bit write for some reason
+ reg_CP_DIV_DENOM = (u32)denominator;
+ while (reg_CP_DIVCNT & 0x8000);
+ return *(REGType32v *)&reg_CP_DIV_RESULT;
}
ARM_FUNC fx32 FX_ModS32(fx32 num, fx32 mod){
- SETREG16(HW_REG_DIVCNT, 0x0);
- SETREG32(HW_REG_DIV_NUMER, (u32)num); //32bit write for some reason
- SETREG64(HW_REG_DIV_DENOM, (u32)mod);
- while (READREG16(HW_REG_DIVCNT) & 0x8000);
- return READREG32(HW_REG_DIVREM_RESULT);
+ reg_CP_DIVCNT = 0x0;
+ *(REGType32v *)&reg_CP_DIV_NUMER = (u32)num; //32bit write for some reason
+ reg_CP_DIV_DENOM = (u32)mod;
+ while (reg_CP_DIVCNT & 0x8000);
+ return *(REGType32v *)&reg_CP_DIVREM_RESULT;
}
diff --git a/arm9/lib/src/FX_vec.c b/arm9/lib/src/FX_vec.c
index af36fe89..95805f33 100644
--- a/arm9/lib/src/FX_vec.c
+++ b/arm9/lib/src/FX_vec.c
@@ -55,10 +55,10 @@ ARM_FUNC fx32 VEC_Mag(struct Vecx32 *a){
fx64 l2 = (fx64)a->x * a->x;
l2 += (fx64)a->y * a->y;
l2 += (fx64)a->z * a->z;
- SETREG16(HW_REG_SQRTCNT, 0x1);
- SETREG64(HW_REG_SQRT_PARAM, l2 * 4);
- while (READREG16(HW_REG_SQRTCNT) & 0x8000); //wait for coprocessor to finish
- return ((fx32)READREG32(HW_REG_SQRT_RESULT) + 1) >> 1;
+ reg_CP_SQRTCNT = 0x1;
+ reg_CP_SQRT_PARAM = l2 * 4;
+ while (reg_CP_SQRTCNT & 0x8000); //wait for coprocessor to finish
+ return ((fx32)reg_CP_SQRT_RESULT + 1) >> 1;
}
ARM_FUNC void VEC_Normalize(struct Vecx32 *a, struct Vecx32 *dst){
@@ -66,15 +66,15 @@ ARM_FUNC void VEC_Normalize(struct Vecx32 *a, struct Vecx32 *dst){
l2 += (fx64)a->y * a->y;
l2 += (fx64)a->z * a->z;
//1/sqrt(l) is computed by calculating sqrt(l)*(1/l)
- SETREG16(HW_REG_DIVCNT, 0x2);
- SETREG64(HW_REG_DIV_NUMER, 0x0100000000000000);
- SETREG64(HW_REG_DIV_DENOM, l2);
- SETREG16(HW_REG_SQRTCNT, 0x1);
- SETREG64(HW_REG_SQRT_PARAM, l2 * 4);
- while (READREG16(HW_REG_SQRTCNT) & 0x8000); //wait for sqrt to finish
- fx32 sqrtresult = READREG32(HW_REG_SQRT_RESULT);
- while (READREG16(HW_REG_DIVCNT) & 0x8000); //wait for division to finish
- l2 = READREG64(HW_REG_DIV_RESULT);
+ reg_CP_DIVCNT = 0x2;
+ reg_CP_DIV_NUMER = 0x0100000000000000;
+ reg_CP_DIV_DENOM = l2;
+ reg_CP_SQRTCNT = 0x1;
+ reg_CP_SQRT_PARAM = l2 * 4;
+ while (reg_CP_SQRTCNT & 0x8000); //wait for sqrt to finish
+ fx32 sqrtresult = reg_CP_SQRT_RESULT;
+ while (reg_CP_DIVCNT & 0x8000); //wait for division to finish
+ l2 = reg_CP_DIV_RESULT;
l2 = sqrtresult * l2;
dst->x = (l2 * a->x + (1LL << (0x2D - 1))) >> 0x2D;
dst->y = (l2 * a->y + (1LL << (0x2D - 1))) >> 0x2D;
@@ -86,15 +86,15 @@ ARM_FUNC void VEC_Fx16Normalize(struct Vecx16 *a, struct Vecx16 *dst){
l2 += a->y * a->y;
l2 += a->z * a->z;
//1/sqrt(l) is computed by calculating sqrt(l)*(1/l)
- SETREG16(HW_REG_DIVCNT, 0x2);
- SETREG64(HW_REG_DIV_NUMER, 0x0100000000000000);
- SETREG64(HW_REG_DIV_DENOM, l2);
- SETREG16(HW_REG_SQRTCNT, 0x1);
- SETREG64(HW_REG_SQRT_PARAM, l2 * 4);
- while (READREG16(HW_REG_SQRTCNT) & 0x8000); //wait for sqrt to finish
- fx32 sqrtresult = READREG32(HW_REG_SQRT_RESULT);
- while (READREG16(HW_REG_DIVCNT) & 0x8000); //wait for division to finish
- l2 = READREG64(HW_REG_DIV_RESULT);
+ reg_CP_DIVCNT = 0x2;
+ reg_CP_DIV_NUMER = 0x0100000000000000;
+ reg_CP_DIV_DENOM = l2;
+ reg_CP_SQRTCNT = 0x1;
+ reg_CP_SQRT_PARAM = l2 * 4;
+ while (reg_CP_SQRTCNT & 0x8000); //wait for sqrt to finish
+ fx32 sqrtresult = reg_CP_SQRT_RESULT;
+ while (reg_CP_DIVCNT & 0x8000); //wait for division to finish
+ l2 = reg_CP_DIV_RESULT;
l2 = sqrtresult * l2;
dst->x = (l2 * a->x + (1LL << (0x2D - 1))) >> 0x2D;
dst->y = (l2 * a->y + (1LL << (0x2D - 1))) >> 0x2D;
diff --git a/arm9/lib/src/OS_arena.c b/arm9/lib/src/OS_arena.c
index eb04e60b..ae05b49c 100644
--- a/arm9/lib/src/OS_arena.c
+++ b/arm9/lib/src/OS_arena.c
@@ -5,8 +5,8 @@
#include "consts.h"
#include "OS_arena.h"
#include "OS_protectionRegion.h"
+#include "OS_emulator.h"
-extern u32 OS_GetConsoleType();
extern BOOL OSi_MainExArenaEnabled;
extern BOOL OSi_Initialized; // TODO: located at 0x021d36f0
void SDK_MAIN_ARENA_LO(); // TODO: technically this should be defined in the lcf
diff --git a/arm9/lib/src/OS_emulator.c b/arm9/lib/src/OS_emulator.c
new file mode 100644
index 00000000..1be0e163
--- /dev/null
+++ b/arm9/lib/src/OS_emulator.c
@@ -0,0 +1,18 @@
+//
+// Created by red031000 on 2020-05-05.
+//
+
+#include "OS_emulator.h"
+#include "function_target.h"
+
+extern u32 OSi_ConsoleTypeCache; //todo fix bss
+
+ARM_FUNC BOOL OS_IsRunOnEmulator() {
+ return FALSE;
+}
+
+ARM_FUNC u32 OS_GetConsoleType() {
+ OSi_ConsoleTypeCache = OS_CONSOLE_NITRO | OS_CONSOLE_DEV_CARD | OS_CONSOLE_SIZE_4MB;
+
+ return OSi_ConsoleTypeCache;
+}
diff --git a/arm9/lib/src/OS_init.c b/arm9/lib/src/OS_init.c
index 90b01ffa..7467c672 100644
--- a/arm9/lib/src/OS_init.c
+++ b/arm9/lib/src/OS_init.c
@@ -7,14 +7,12 @@
extern void PXI_Init();
extern void OS_InitLock();
-extern void OS_InitIrqTable();
extern void OS_SetIrqStackChecker();
extern void OS_InitException();
extern void MI_Init();
extern void OS_InitVAlarm();
extern void OSi_InitVramExclusive();
extern void OS_InitThread();
-extern void OS_InitReset();
extern void CTRDG_Init();
extern void CARD_Init();
extern void PM_Init();
diff --git a/arm9/lib/src/OS_interrupt.c b/arm9/lib/src/OS_interrupt.c
new file mode 100644
index 00000000..1fb43821
--- /dev/null
+++ b/arm9/lib/src/OS_interrupt.c
@@ -0,0 +1,89 @@
+//
+// Created by red031000 on 2020-05-07.
+//
+
+#include "consts.h"
+#include "function_target.h"
+#include "OS_interrupt.h"
+#include "OS_thread.h"
+
+#pragma optimize_for_size on
+
+extern OSThreadQueue OSi_IrqThreadQueue;
+extern OSIrqMask OS_EnableIrqMask(OSIrqMask intr);
+
+ARM_FUNC void OS_InitIrqTable() {
+ OS_InitThreadQueue(&OSi_IrqThreadQueue);
+}
+
+ARM_FUNC void OS_SetIrqFunction(OSIrqMask intrBit, OSIrqFunction function) {
+ s32 i;
+ OSIrqCallbackInfo *info;
+
+ for (i = 0; i < 0x16; i++) {
+ if (intrBit & 1) {
+ info = NULL;
+
+ if (8 <= i && i <= 11) {
+ info = &OSi_IrqCallbackInfo[i - 8];
+ }
+ else if (3 <= i && i <= 6) {
+ info = &OSi_IrqCallbackInfo[i - 3 + 4];
+ }
+ else {
+ OS_IRQTable[i] = function;
+ }
+
+ if (info) {
+ info->func = (void (*)(void *))function;
+ info->arg = 0;
+ info->enable = TRUE;
+ }
+ }
+ intrBit >>= 1;
+ }
+}
+
+ARM_FUNC OSIrqFunction OS_GetIrqFunction(OSIrqMask intrBit) {
+ s32 i = 0;
+ OSIrqFunction *funcPtr = &OS_IRQTable[0];
+
+ do {
+ if (intrBit & 1)
+ {
+ if (8 <= i && i <= 11) {
+ i = i - 8;
+ return (void (*)(void))OSi_IrqCallbackInfo[i].func;
+ }
+ else if (3 <= i && i <= 6) {
+ i++;
+ return (void (*)(void))OSi_IrqCallbackInfo[i].func;
+ }
+
+ return *funcPtr;
+ }
+ intrBit >>= 1;
+ funcPtr++;
+ i++;
+ } while (i < 0x16);
+ return 0;
+}
+
+ARM_FUNC void OSi_EnterDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg)
+{
+ OSIrqMask mask = 1UL << (dmaNo + 8);
+ OSi_IrqCallbackInfo[dmaNo].func = callback;
+ OSi_IrqCallbackInfo[dmaNo].arg = arg;
+
+ OSi_IrqCallbackInfo[dmaNo].enable = OS_EnableIrqMask(mask) & mask;
+}
+
+ARM_FUNC void OSi_EnterTimerCallback(u32 timerNo, void (*callback) (void *), void *arg)
+{
+ OSIrqMask mask = 1UL << (timerNo + 3);
+ OSi_IrqCallbackInfo[timerNo + 4].func = callback;
+ OSi_IrqCallbackInfo[timerNo + 4].arg = arg;
+
+ (void)OS_EnableIrqMask(mask);
+ OSi_IrqCallbackInfo[timerNo + 4].enable = TRUE;
+}
diff --git a/arm9/lib/src/OS_printf.c b/arm9/lib/src/OS_printf.c
new file mode 100644
index 00000000..ba484df8
--- /dev/null
+++ b/arm9/lib/src/OS_printf.c
@@ -0,0 +1,1248 @@
+#include "global.h"
+#include "OS_printf.h"
+
+struct printfStr
+{
+ s32 spaceLeft;
+ s8 *stringEnd;
+ s8 *stringStart;
+};
+
+void string_put_char(struct printfStr *dest, s8 value);
+void string_fill_char(struct printfStr *dest, s8 value, s32 count);
+void string_put_string(struct printfStr *dest, const s8 *src, s32 count);
+
+
+#ifndef NONMATCHING
+// c definition is at the bottom of the file
+u64 _ll_udiv(u64 a, u64 b);
+
+ARM_FUNC asm s32 OS_VSNPrintf(s8 *buffer, s32 bufsz, const s8 *format, void *args)
+{
+ stmdb sp!, {r4-r11,lr}
+ sub sp, sp, #0x64
+ mov r9, r2
+ str r1, [sp, #0x54]
+ str r0, [sp, #0x5c]
+ str r0, [sp, #0x58]
+ ldrsb r0, [r9, #0x0]
+ str r1, [sp, #0x0]
+ mov r11, r3
+ cmp r0, #0x0
+ beq _020CAD18
+ mov r0, #0xa
+ str r0, [sp, #0xc]
+ mov r0, #0x0
+ str r0, [sp, #0x4]
+ mov r0, #0x20
+ str r0, [sp, #0x1c]
+ mov r0, #0x30
+ str r0, [sp, #0x20]
+ mvn r0, #0x0
+ str r0, [sp, #0x8]
+ mov r0, #0x57
+ str r0, [sp, #0x10]
+ mov r0, #0x8
+ str r0, [sp, #0x14]
+ mov r0, #0x37
+ str r0, [sp, #0x18]
+ mov r0, #0x10
+ str r0, [sp, #0x24]
+ mov r0, #0x1
+ str r0, [sp, #0x28]
+ mov r0, #0x2b
+ str r0, [sp, #0x34]
+ mov r0, #0x2d
+ str r0, [sp, #0x30]
+ mov r0, #0x2
+ str r0, [sp, #0x2c]
+_020CA530:
+ ldrsb r1, [r9, #0x0]
+ and r0, r1, #0xff
+ eor r0, r0, #0x20
+ sub r0, r0, #0xa1
+ cmp r0, #0x3c
+ bhs _020CA56C
+ add r0, sp, #0x54
+ bl string_put_char
+ ldrsb r1, [r9, #0x1]!
+ cmp r1, #0x0
+ beq _020CAD0C
+ add r0, sp, #0x54
+ add r9, r9, #0x1
+ bl string_put_char
+ b _020CAD0C
+_020CA56C:
+ cmp r1, #0x25
+ beq _020CA584
+ add r0, sp, #0x54
+ add r9, r9, #0x1
+ bl string_put_char
+ b _020CAD0C
+_020CA584:
+ ldr r6, [sp, #0x4]
+ ldr r5, [sp, #0x8]
+ ldr r2, [sp, #0xc]
+ ldr r0, [sp, #0x10]
+ mov r10, r6
+ mov r3, r9
+_020CA59C:
+ ldrsb r4, [r9, #0x1]!
+ cmp r4, #0x20
+ bgt _020CA5B4
+ cmp r4, #0x20
+ beq _020CA5F4
+ b _020CA60C
+_020CA5B4:
+ cmp r4, #0x30
+ bgt _020CA60C
+ cmp r4, #0x2b
+ blt _020CA60C
+ cmp r4, #0x2b
+ beq _020CA5E0
+ cmp r4, #0x2d
+ beq _020CA5FC
+ cmp r4, #0x30
+ beq _020CA604
+ b _020CA60C
+_020CA5E0:
+ ldrsb r1, [r9, #-0x1]
+ cmp r1, #0x20
+ bne _020CA60C
+ orr r6, r6, #0x2
+ b _020CA59C
+_020CA5F4:
+ orr r6, r6, #0x1
+ b _020CA59C
+_020CA5FC:
+ orr r6, r6, #0x8
+ b _020CA59C
+_020CA604:
+ orr r6, r6, #0x10
+ b _020CA59C
+_020CA60C:
+ cmp r4, #0x2a
+ bne _020CA640
+ add r11, r11, #0x4
+ ldr r10, [r11, #-0x4]
+ add r9, r9, #0x1
+ cmp r10, #0x0
+ rsblt r10, r10, #0x0
+ orrlt r6, r6, #0x8
+ b _020CA654
+_020CA630:
+ ldrsb r4, [r9], #0x1
+ mov r1, #0xa
+ mla r1, r10, r1, r4
+ sub r10, r1, #0x30
+_020CA640:
+ ldrsb r1, [r9, #0x0]
+ cmp r1, #0x30
+ blt _020CA654
+ cmp r1, #0x39
+ ble _020CA630
+_020CA654:
+ ldrsb r1, [r9, #0x0]
+ cmp r1, #0x2e
+ bne _020CA6AC
+ ldrsb r1, [r9, #0x1]!
+ ldr r5, [sp, #0x4]
+ cmp r1, #0x2a
+ bne _020CA698
+ add r11, r11, #0x4
+ ldr r5, [r11, #-0x4]
+ add r9, r9, #0x1
+ cmp r5, #0x0
+ ldrlt r5, [sp, #0x8]
+ b _020CA6AC
+_020CA688:
+ ldrsb r4, [r9], #0x1
+ mov r1, #0xa
+ mla r1, r5, r1, r4
+ sub r5, r1, #0x30
+_020CA698:
+ ldrsb r1, [r9, #0x0]
+ cmp r1, #0x30
+ blt _020CA6AC
+ cmp r1, #0x39
+ ble _020CA688
+_020CA6AC:
+ ldrsb r1, [r9, #0x0]
+ cmp r1, #0x68
+ beq _020CA6C4
+ cmp r1, #0x6c
+ beq _020CA6DC
+ b _020CA6F0
+_020CA6C4: // h
+ ldrsb r1, [r9, #0x1]!
+ cmp r1, #0x68
+ orrne r6, r6, #0x40
+ addeq r9, r9, #0x1
+ orreq r6, r6, #0x100
+ b _020CA6F0
+_020CA6DC: // l
+ ldrsb r1, [r9, #0x1]!
+ cmp r1, #0x6c
+ orrne r6, r6, #0x20
+ addeq r9, r9, #0x1
+ orreq r6, r6, #0x80
+_020CA6F0:
+ ldrsb r1, [r9, #0x0]
+ cmp r1, #0x69
+ bgt _020CA740
+ cmp r1, #0x63
+ blt _020CA720
+ cmp r1, #0x63
+ beq _020CA7B4
+ cmp r1, #0x64
+ beq _020CA96C
+ cmp r1, #0x69
+ beq _020CA96C
+ b _020CA950
+_020CA720:
+ cmp r1, #0x25
+ bgt _020CA734
+ cmp r1, #0x25
+ beq _020CA934
+ b _020CA950
+_020CA734:
+ cmp r1, #0x58
+ beq _020CA7A0
+ b _020CA950
+_020CA740:
+ cmp r1, #0x6e
+ bgt _020CA754
+ cmp r1, #0x6e
+ beq _020CA8DC
+ b _020CA950
+_020CA754:
+ sub r1, r1, #0x6f
+ cmp r1, #0x9
+ addls pc, pc, r1, lsl #0x2
+ b _020CA950
+_020CA764:
+ b _020CA78C
+ b _020CA7A8
+ b _020CA950
+ b _020CA950
+ b _020CA828
+ b _020CA950
+ b _020CA798
+ b _020CA950
+ b _020CA950
+ b _020CA964
+_020CA78C:
+ ldr r2, [sp, #0x14]
+ orr r6, r6, #0x1000
+ b _020CA96C
+_020CA798:
+ orr r6, r6, #0x1000
+ b _020CA96C
+_020CA7A0:
+ ldr r0, [sp, #0x18]
+ b _020CA964
+_020CA7A8:
+ orr r6, r6, #0x4
+ ldr r5, [sp, #0x14]
+ b _020CA964
+_020CA7B4:
+ cmp r5, #0x0
+ bge _020CA950
+ ands r0, r6, #0x8
+ add r11, r11, #0x4
+ ldr r4, [r11, #-0x4]
+ beq _020CA7F0
+ mov r0, r4, lsl #0x18
+ mov r1, r0, asr #0x18
+ add r0, sp, #0x54
+ bl string_put_char
+ ldr r1, [sp, #0x1c]
+ sub r2, r10, #0x1
+ add r0, sp, #0x54
+ bl string_fill_char
+ b _020CA820
+_020CA7F0:
+ ands r0, r6, #0x10
+ ldrne r0, [sp, #0x20]
+ sub r2, r10, #0x1
+ ldreq r0, [sp, #0x1c]
+ mov r0, r0, lsl #0x18
+ mov r1, r0, asr #0x18
+ add r0, sp, #0x54
+ bl string_fill_char
+ mov r0, r4, lsl #0x18
+ mov r1, r0, asr #0x18
+ add r0, sp, #0x54
+ bl string_put_char
+_020CA820:
+ add r9, r9, #0x1
+ b _020CAD0C
+_020CA828:
+ add r11, r11, #0x4
+ cmp r5, #0x0
+ ldr r7, [sp, #0x4]
+ ldr r4, [r11, #-0x4]
+ bge _020CA860
+ ldrsb r0, [r4]
+ cmp r0, #0x0
+ beq _020CA874
+_020CA848:
+ add r7, r7, #0x1
+ ldrsb r0, [r4, r7]
+ cmp r0, #0x0
+ bne _020CA848
+ b _020CA874
+_020CA85C:
+ add r7, r7, #0x1
+_020CA860:
+ cmp r7, r5
+ bge _020CA874
+ ldrsb r0, [r4, r7]
+ cmp r0, #0x0
+ bne _020CA85C
+_020CA874:
+ ands r0, r6, #0x8
+ sub r10, r10, r7
+ beq _020CA8A4
+ mov r1, r4
+ mov r2, r7
+ add r0, sp, #0x54
+ bl string_put_string
+ ldr r1, [sp, #0x1C]
+ mov r2, r10
+ add r0, sp, #0x54
+ bl string_fill_char
+ b _020CA8D4
+_020CA8A4:
+ ands r0, r6, #0x10
+ ldrne r0, [sp, #0x20]
+ mov r2, r10
+ ldreq r0, [sp, #0x1C]
+ mov r0, r0, lsl #0x18
+ mov r1, r0, asr #0x18
+ add r0, sp, #0x54
+ bl string_fill_char
+ mov r1, r4
+ mov r2, r7
+ add r0, sp, #0x54
+ bl string_put_string
+_020CA8D4:
+ add r9, r9, #0x1
+ b _020CAD0C
+_020CA8DC:
+ ands r0, r6, #0x100
+ ldr r1, [sp, #0x58]
+ ldr r0, [sp, #0x5c]
+ sub r2, r1, r0
+ bne _020CA92C
+ ands r0, r6, #0x40
+ addne r11, r11, #0x4
+ ldrne r0, [r11, #-0x4]
+ strneh r2, [r0, #0x0]
+ bne _020CA92C
+ ands r0, r6, #0x80
+ addeq r11, r11, #0x4
+ ldreq r0, [r11, #-0x4]
+ streq r2, [r0, #0x0]
+ beq _020CA92C
+ add r11, r11, #0x4
+ ldr r0, [r11, #-0x4]
+ mov r1, r2, asr #0x1f
+ str r2, [r0, #0x0]
+ str r1, [r0, #0x4]
+_020CA92C:
+ add r9, r9, #0x1
+ b _020CAD0C
+_020CA934:
+ add r0, r3, #0x1
+ cmp r0, r9
+ bne _020CA950
+ add r0, sp, #0x54
+ add r9, r9, #0x1
+ bl string_put_char
+ b _020CAD0C
+_020CA950:
+ add r0, sp, #0x54
+ mov r1, r3
+ sub r2, r9, r3
+ bl string_put_string
+ b _020CAD0C
+_020CA964:
+ ldr r2, [sp, #0x24]
+ orr r6, r6, #0x1000
+_020CA96C:
+ ands r1, r6, #0x8
+ bicne r6, r6, #0x10
+ cmp r5, #0x0
+ bicge r6, r6, #0x10
+ ldrlt r5, [sp, #0x28]
+ ldr r7, [sp, #0x4]
+ ands r1, r6, #0x1000
+ beq _020CAA20
+ ands r1, r6, #0x100
+ addne r11, r11, #0x4
+ ldrneb r4, [r11, #-0x4]
+ movne r1, #0x0
+ bne _020CA9D0
+ ands r1, r6, #0x40
+ addne r11, r11, #0x4
+ ldrneh r4, [r11, #-0x4]
+ movne r1, #0x0
+ bne _020CA9D0
+ ands r1, r6, #0x80
+ addne r11, r11, #0x8
+ ldrne r1, [r11, #-0x4]
+ ldrne r4, [r11, #-0x8]
+ addeq r11, r11, #0x4
+ ldreq r4, [r11, #-0x4]
+ moveq r1, #0x0
+_020CA9D0:
+ bic r6, r6, #0x3
+ ands r3, r6, #0x4
+ beq _020CAAD8
+ cmp r2, #0x10
+ bne _020CAA0C
+ mov r3, #0x0
+ cmp r1, r3
+ cmpeq r4, r3
+ beq _020CAAD8
+ ldr r3, [sp, #0x20]
+ ldr r7, [sp, #0x2c]
+ strb r3, [sp, #0x39]
+ add r3, r0, #0x21
+ strb r3, [sp, #0x38]
+ b _020CAAD8
+_020CAA0C:
+ cmp r2, #0x8
+ ldreq r3, [sp, #0x20]
+ ldreq r7, [sp, #0x28]
+ streqb r3, [sp, #0x38]
+ b _020CAAD8
+_020CAA20:
+ ands r1, r6, #0x100
+ addne r11, r11, #0x4
+ ldrnesb r4, [r11, #-0x4]
+ movne r1, r4, asr #0x1f
+ bne _020CAA64
+ ands r1, r6, #0x40
+ addne r11, r11, #0x4
+ ldrnesh r4, [r11, #-0x4]
+ movne r1, r4, asr #0x1f
+ bne _020CAA64
+ ands r1, r6, #0x80
+ addne r11, r11, #0x8
+ ldrne r4, [r11, #-0x8]
+ ldrne r1, [r11, #-0x4]
+ addeq r11, r11, #0x4
+ ldreq r4, [r11, #-0x4]
+ moveq r1, r4, asr #0x1f
+_020CAA64:
+ mov r3, #0x0
+ and r8, r3, #0x0
+ cmp r8, r3
+ and r8, r1, #0x80000000
+ cmpeq r8, r3
+ beq _020CAAA0
+ ldr r7, [sp, #0x30]
+ mvn r4, r4
+ strb r7, [sp, #0x38]
+ mvn r7, r1
+ mov r1, #0x1
+ adds r4, r4, r1
+ adc r1, r7, r3
+ ldr r7, [sp, #0x28]
+ b _020CAAD8
+_020CAAA0:
+ cmp r1, r3
+ cmpeq r4, r3
+ bne _020CAAB4
+ cmp r5, #0x0
+ beq _020CAAD8
+_020CAAB4:
+ ands r3, r6, #0x2
+ ldrne r3, [sp, #0x34]
+ ldrne r7, [sp, #0x28]
+ strneb r3, [sp, #0x38]
+ bne _020CAAD8
+ ands r3, r6, #0x1
+ ldrne r3, [sp, #0x1c]
+ ldrne r7, [sp, #0x28]
+ strneb r3, [sp, #0x38]
+_020CAAD8:
+ cmp r2, #0x8
+ ldr r8, [sp, #0x4]
+ beq _020CAAF8
+ cmp r2, #0xa
+ beq _020CAB40
+ cmp r2, #0x10
+ beq _020CABDC
+ b _020CAC28
+_020CAAF8:
+ mov r0, #0x0
+ cmp r1, r0
+ cmpeq r4, r0
+ beq _020CAC28
+_020CAB08:
+ and r0, r4, #0x7
+ add r3, r0, #0x30
+ add r0, sp, #0x3a
+ strb r3, [r0, r8]
+ mov r4, r4, lsr #0x3
+ mov r2, #0x0
+ mov r0, r1, lsr #0x3
+ orr r4, r4, r1, lsl #0x1d
+ cmp r0, r2
+ cmpeq r4, r2
+ mov r1, r0
+ add r8, r8, #0x1
+ bne _020CAB08
+ b _020CAC28
+_020CAB40:
+ mov r0, #0x0
+ cmp r0, r0
+ cmpeq r1, r0
+ bne _020CAB8C
+ cmp r4, #0x0
+ beq _020CAC28
+_020CAB58:
+ ldr r0, =0xCCCCCCCD
+ umull r1, r0, r4, r0
+ movs r0, r0, lsr #0x3
+ mov r1, #0xa
+ mul r1, r0, r1
+ sub r1, r4, r1
+ mov r4, r0
+ add r1, r1, #0x30
+ add r0, sp, #0x3a
+ strb r1, [r0, r8]
+ add r8, r8, #0x1
+ bne _020CAB58
+ b _020CAC28
+_020CAB8C:
+ cmp r1, r0
+ cmpeq r4, r0
+ beq _020CAC28
+_020CAB98:
+ ldr r2, [sp, #0xc]
+ ldr r3, [sp, #0x4]
+ mov r0, r4
+ bl _ll_udiv
+ mov r3, #0xa
+ umull r3, r12, r0, r3
+ subs r3, r4, r3
+ mov r2, #0x0
+ add r4, r3, #0x30
+ add r3, sp, #0x3a
+ strb r4, [r3, r8]
+ cmp r1, r2
+ cmpeq r0, r2
+ mov r4, r0
+ add r8, r8, #0x1
+ bne _020CAB98
+ b _020CAC28
+_020CABDC:
+ mov r2, #0x0
+ cmp r1, r2
+ cmpeq r4, r2
+ beq _020CAC28
+_020CABEC:
+ and r3, r4, #0xf
+ cmp r3, #0xa
+ mov r4, r4, lsr #0x4
+ addlt r3, r3, #0x30
+ mov r2, r1, lsr #0x4
+ orr r4, r4, r1, lsl #0x1c
+ mov r1, r2
+ addge r3, r3, r0
+ add r2, sp, #0x3a
+ strb r3, [r2, r8]
+ mov r2, #0x0
+ cmp r1, r2
+ add r8, r8, #0x1
+ cmpeq r4, r2
+ bne _020CABEC
+_020CAC28:
+ cmp r7, #0x0
+ ble _020CAC4C
+ ldrsb r0, [sp, #0x38]
+ cmp r0, #0x30
+ ldreq r1, [sp, #0x20]
+ addeq r0, sp, #0x3a
+ streqb r1, [r0, r8]
+ ldreq r7, [sp, #0x4]
+ addeq r8, r8, #0x1
+_020CAC4C:
+ sub r5, r5, r8
+ ands r0, r6, #0x10
+ beq _020CAC68
+ sub r0, r10, r8
+ sub r0, r0, r7
+ cmp r5, r0
+ movlt r5, r0
+_020CAC68:
+ cmp r5, #0x0
+ subgt r10, r10, r5
+ add r0, r7, r8
+ ands r6, r6, #0x8
+ sub r10, r10, r0
+ bne _020CAC90
+ ldr r1, [sp, #0x1c]
+ add r0, sp, #0x54
+ mov r2, r10
+ bl string_fill_char
+_020CAC90:
+ cmp r7, #0x0
+ ble _020CACB8
+ add r0, sp, #0x38
+ add r4, r0, r7
+_020CACA0:
+ ldrsb r1, [r4, #-0x1]!
+ sub r7, r7, #0x1
+ add r0, sp, #0x54
+ bl string_put_char
+_020CACB0:
+ cmp r7, #0x0
+ bgt _020CACA0
+_020CACB8:
+ ldr r1, [sp, #0x20]
+ mov r2, r5
+ add r0, sp, #0x54
+ bl string_fill_char
+ cmp r8, #0x0
+ ble _020CACF0
+ add r0, sp, #0x3A
+ add r4, r0, r8
+_020CACD8:
+ ldrsb r1, [r4, #-0x1]!
+ sub r8, r8, #0x1
+ add r0, sp, #0x54
+ bl string_put_char
+ cmp r8, #0x0
+ bgt _020CACD8
+_020CACF0:
+ cmp r6, #0x0
+ beq _020CAD08
+ ldr r1, [sp, #0x1C]
+ mov r2, r10
+ add r0, sp, #0x54
+ bl string_fill_char
+_020CAD08:
+ add r9, r9, #0x1
+_020CAD0C:
+ ldrsb r0, [r9, #0x0]
+ cmp r0, #0x0
+ bne _020CA530
+_020CAD18:
+ ldr r0, [sp, #0x54]
+ cmp r0, #0x0
+ ldrne r0, [sp, #0x58]
+ movne r1, #0x0
+ strneb r1, [r0, #0x0]
+ bne _020CAD48
+ ldr r0, [sp, #0x0]
+ cmp r0, #0x0
+ ldrne r1, [sp, #0x5c]
+ movne r2, #0x0
+ addne r0, r1, r0
+ strneb r2, [r0, #-0x1]
+_020CAD48:
+ ldr r1, [sp, #0x58]
+ ldr r0, [sp, #0x5c]
+ sub r0, r1, r0
+ add sp, sp, #0x64
+ ldmia sp!, {r4-r11,lr}
+ bx lr
+}
+#endif
+
+ARM_FUNC void string_put_char(struct printfStr *dest, s8 value)
+{
+ if (dest->spaceLeft != 0)
+ {
+ dest->stringEnd[0] = value;
+ dest->spaceLeft--;
+ }
+ dest->stringEnd++;
+}
+
+ARM_FUNC void string_fill_char(struct printfStr *dest, s8 value, s32 count)
+{
+ if (count <= 0)
+ return;
+
+ u32 written = 0;
+ u32 spaceLeft = (u32)dest->spaceLeft;
+ u32 toWrite = spaceLeft > (u32)count ? count : spaceLeft;
+
+ while (written < toWrite)
+ {
+ dest->stringEnd[written] = value;
+ written++;
+ }
+
+ dest->spaceLeft -= toWrite;
+ dest->stringEnd += count; // this is wrong but matching...
+}
+
+ARM_FUNC void string_put_string(struct printfStr *dest, const s8 *src, s32 count)
+{
+ if (count <= 0)
+ return;
+
+ u32 written = 0;
+ u32 spaceLeft = (u32)dest->spaceLeft;
+ u32 toWrite = spaceLeft > (u32)count ? count : spaceLeft;
+
+ while (written < toWrite)
+ {
+ dest->stringEnd[written] = src[written];
+ written++;
+ }
+
+ dest->spaceLeft -= toWrite;
+ dest->stringEnd += count; // this is wrong but matching...
+}
+
+ARM_FUNC s32 OS_SPrintf(s8 *buffer, const s8 *format, ...)
+{
+ void *args = (void *)((u32 *)((u32)&format & ~0x3) + 1); // hack since mwccarm doesn't have <stdarg.h> apparently
+ return OS_VSPrintf(buffer, format, args);
+}
+
+ARM_FUNC s32 OS_VSPrintf(s8 *buffer, const s8 *format, void *args)
+{
+ return OS_VSNPrintf(buffer, 0x7FFFFFFF, format, args);
+}
+
+ARM_FUNC s32 OS_SNPrintf(s8 *buffer, s32 bufsz, const s8 *format, ...)
+{
+ void *args = (void *)((u32 *)((u32)&format & ~0x3) + 1); // hack since mwccarm doesn't have <stdarg.h> apparently
+ return OS_VSNPrintf(buffer, bufsz, format, args);
+}
+
+#ifdef NONMATCHING
+
+struct Unk
+{
+ s32 unk00;
+ s32 unk04;
+ s32 unk08;
+ s32 unk0C;
+ s32 unk10;
+ s32 unk14;
+ s32 unk18;
+ s32 unk1C;
+ s32 unk20;
+ s32 unk24;
+ s32 unk28;
+ s32 unk2C;
+ s32 unk30;
+ s32 unk34;
+ s8 unk38;
+ s8 unk39;
+ s8 unk3A;
+ // not sure about this struct's size or even if it's a single struct
+};
+
+#define va_arg(list, ty) *(ty *)((u32 *)(list = (void *)((u32 *)(list) + 1)) - 1)
+#define va_arg_64(list, sgn) *((sgn##64 *)(list = (void *)((sgn##64 *)(list) + 1)) - 1)
+
+ARM_FUNC s32 OS_VSNPrintf(s8 *buffer, s32 bufsz, const s8 *format, void *args)
+{
+ struct printfStr str;
+ struct Unk unk;
+ str.spaceLeft = bufsz;
+ str.stringStart = buffer;
+ str.stringEnd = buffer;
+
+ if (*format != 0)
+ {
+ // these assignments are likely wrong
+ unk.unk04 = 0;
+ unk.unk0C = 10;
+ unk.unk1C = 32;
+ unk.unk20 = 48;
+ unk.unk08 = 0;
+ unk.unk10 = 87;
+ unk.unk14 = 8;
+ unk.unk18 = 55;
+ unk.unk24 = 16;
+ unk.unk28 = 1;
+ unk.unk34 = 43;
+ unk.unk30 = 45;
+ unk.unk2C = 2;
+
+
+ do
+ {
+ s8 c = *format;
+ u32 x = (u8)c;
+
+ // matches:
+ // binary range (hex range) [dec range]
+ // 1000 0001-1001 1111 (0x81-0x9F) [129-159]
+ // 1110 0000-1111 1100 (0xE0-0xFC) [224-252]
+ if ((x ^ 0x20) - 0xa1 < 0x3c)
+ {
+ string_put_char(&str, c);
+ c = *(++format);
+ if (c != 0)
+ {
+ format++;
+ string_put_char(&str, c);
+ }
+ }
+ else if (c != '%')
+ {
+ format++;
+ string_put_char(&str, c);
+ }
+ else
+ {
+ s32 flags = unk.unk04;
+ s32 r5 = unk.unk08;
+ s32 r2 = unk.unk0C;
+ s32 r0 = unk.unk10;
+ s32 r10 = flags;
+ const s8 *r3 = format;
+ s8 r4;
+ while (1)
+ {
+ r4 = *(++format);
+ switch (r4)
+ {
+ case '+':
+ c = *(format - 1);
+ if (c == ' ')
+ goto post_padding;
+ flags |= 0x2;
+ break;
+ case ' ':
+ flags |= 0x1;
+ break;
+ case '-':
+ flags |= 0x8;
+ break;
+ case '0':
+ flags |= 0x10;
+ break;
+ default:
+ goto post_padding;
+ }
+ }
+ post_padding:
+ if (r4 == '*')
+ {
+ u32 v = va_arg(args, u32);
+ format++;
+ if (v < 0)
+ {
+ r10 = -r10;
+ flags |= 0x8;
+ }
+ }
+ else
+ {
+ for (c = *format; c >= '0' && c <= '9'; c = *format)
+ {
+ s8 d = *(format++);
+ r10 = (r10 * 10 + d) - '0';
+ }
+ }
+
+ c = *format;
+ if (c == '.')
+ {
+ c = *(++format);
+ r5 = unk.unk04;
+ if (c == '*')
+ {
+ u32 v = va_arg(args, u32);
+ format++;
+ if (v < 0)
+ {
+ r5 = unk.unk08;
+ }
+ }
+ for (c = *format; c >= '0' && c <= '9'; c = *format)
+ {
+ s8 d = *(format++);
+ r5 = (r5 * 10 + d) - '0';
+ }
+ }
+
+ c = *format;
+ switch (c)
+ {
+ case 'h':
+ c = *format++;
+ if (c != 'h')
+ {
+ flags |= 0x40;
+ format++;
+ flags |= 0x100;
+ }
+ break;
+ case 'l':
+ c = *format++;
+ if (c != 'l')
+ {
+ flags |= 0x20;
+ format++;
+ flags |= 0x80;
+ }
+ break;
+ }
+
+ c = *format;
+ switch (c)
+ {
+ case 'o':
+ r2 = unk.unk14;
+ flags |= 0x1000;
+ break;
+ case 'u':
+ flags |= 0x1000;
+ break;
+ case 'X':
+ r0 = unk.unk18;
+ goto case_x;
+ case 'p':
+ flags |= 0x4;
+ r5 = unk.unk14;
+ case 'c':
+ if ((s32)r5 < 0)
+ {
+ r0 = flags & 0x8;
+ u32 v = va_arg(args, u32);
+ if (r0)
+ {
+ string_put_char(&str, (s8)v);
+ string_fill_char(&str, (s8)unk.unk1C, r10 - 1);
+ }
+ else
+ {
+ r0 = flags & 0x10;
+ if (r0)
+ r0 = unk.unk20;
+ else
+ r0 = unk.unk1C;
+ string_fill_char(&str, (s8)r0, r10 - 1);
+ string_put_char(&str, (s8)v);
+ }
+ format++;
+ }
+ break;
+ case 's':
+ {
+ s8 *v = *(((s8 **)args)++);
+ s32 count = unk.unk04;
+ if (r5 < 0)
+ {
+ while (v[count] != 0)
+ {
+ count++;
+ }
+ }
+ else
+ {
+ while (count < r5 && v[count] != 0)
+ {
+ count++;
+ }
+ }
+ r0 = flags & 0x8;
+ r10 = r10 - count;
+ if (r0)
+ {
+ string_put_string(&str, v, count);
+ string_fill_char(&str, (s8)unk.unk1C, r10);
+ }
+ else
+ {
+ r0 = flags & 0x10;
+ if (r0)
+ r0 = unk.unk20;
+ else
+ r0 = unk.unk1C;
+ string_fill_char(&str, (s8)r0, r10 - 1);
+ string_put_string(&str, v, count);
+ }
+ format++;
+ break;
+ }
+ case 'n':
+ {
+ r0 = flags & 0x100;
+ s32 count = str.stringEnd - str.stringStart;
+ if (!r0)
+ {
+ if (flags & 0x40)
+ {
+ s16 *v = va_arg(args, s16 *);
+ *v = (s16)count;
+ }
+ else if (flags & 0x80)
+ {
+ s64 *v = va_arg(args, s64 *);
+ *v = count;
+ }
+ else
+ {
+ s64 *v = va_arg(args, s64 *);
+ *v = count;
+ }
+ }
+ format++;
+ }
+ case '%':
+ if (r3 + 1 == format)
+ {
+ format++;
+ string_put_char(&str, c);
+ break;
+ }
+ else
+ {
+ string_put_string(&str, r3, format - r3);
+ break;
+ }
+ case 'x':
+ case_x:
+ r2 = unk.unk24;
+ flags |= 0x1000;
+ case 'd':
+ case 'i':
+ if (flags & 0x8)
+ {
+ flags = flags & ~0x10;
+ }
+ if (r5 >= 0)
+ {
+ flags = flags & ~0x10;
+ }
+ else
+ {
+ r5 = unk.unk28;
+ }
+ s32 r7 = unk.unk04;
+ u64 value;
+ if (flags & 0x1000)
+ {
+ if (flags & 0x100)
+ {
+ value = va_arg(args, u8);
+ }
+ else if (flags & 0x40)
+ {
+ value = va_arg(args, u16);
+ }
+ else if (flags & 0x80)
+ {
+ value = va_arg_64(args, u);
+ }
+ else
+ {
+ value = va_arg(args, u32);
+ }
+ flags = flags & ~0x3;
+ if (flags & 0x4)
+ {
+ if (r2 == 0x10)
+ {
+ if (value != 0)
+ {
+ s32 something = unk.unk20;
+ s32 somethingElse = unk.unk2C;
+ unk.unk39 = (s8)something;
+ unk.unk38 = (s8)(something + 0x21);
+ // 0x21 could be 'a'-'A'+1
+ }
+ }
+ else
+ {
+ if (r2 == 0x8)
+ {
+ s32 something = unk.unk20;
+ r7 = unk.unk28;
+ unk.unk38 = (s8)(something);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (flags & 0x100)
+ {
+ s32 x = (s32)va_arg(args, s8);
+ value = (u64)x;
+ }
+ else if (flags & 0x40)
+ {
+ s32 x = (s32)va_arg(args, s16);
+ value = (u64)x;
+ }
+ else if (flags & 0x80)
+ {
+ s64 dWord = va_arg_64(args, s);
+ value = (u64)dWord;
+ }
+ else
+ {
+ s32 x = va_arg(args, s32);
+ value = (u64)value;
+ }
+
+ if (value & 0x8000000000000000)
+ {
+ unk.unk38 = (s8)unk.unk30;
+ value = ~value + 1;
+ r7 = unk.unk28;
+ }
+ else
+ {
+ if (value || r5)
+ {
+ if (flags & 0x2)
+ {
+ r7 = unk.unk28;
+ unk.unk38 = (s8)unk.unk34;
+ }
+ else if (flags & 0x1)
+ {
+ r7 = unk.unk28;
+ unk.unk38 = (s8)unk.unk1C;
+ }
+ }
+ }
+ s32 r8 = flags;
+ switch (r2)
+ {
+ case 8:
+ while (value != 0)
+ {
+ u32 octDig = ((u32)value & 0x7) + '0';
+ s8 *p = &unk.unk3A;
+ p[r8] = (s8)octDig;
+ value = value >> 3;
+ r8++;
+ }
+ break;
+ case 10:
+ if (value >> 32 == 0)
+ {
+ u32 v = (u32)value;
+ while (v)
+ {
+ u32 div10 = v / 10;
+ u32 dig = v - div10;
+ v = div10;
+ s8 *p = &unk.unk3A;
+ p[r8] = (s8)dig;
+ r8++;
+ }
+ }
+ else
+ {
+ while (value)
+ {
+ u64 div10 = value / 10;
+ u32 dig = (u32)(value - div10);
+ value = div10;
+ s8 *p = &unk.unk3A;
+ p[r8] = (s8)dig;
+ r8++;
+ }
+ }
+ break;
+ case 16:
+ while (value != 0)
+ {
+ u32 hexDig = ((u32)value & 0xf);
+ value = value >> 4;
+ if (hexDig < 10)
+ hexDig = hexDig + '0';
+ else
+ hexDig = hexDig + r0;
+ s8 *p = &unk.unk3A;
+ p[r8] = (s8)hexDig;
+ r8++;
+ }
+ break;
+ }
+ if (r7 > 0)
+ {
+ if (unk.unk38 == '0')
+ {
+ s8 *p = &unk.unk3A;
+ p[r8] = (s8)unk.unk20;
+ r7 = flags;
+ r8++;
+ }
+ r5 = r5 - r8;
+ if (flags & 0x10)
+ {
+ if (r5 < r10 - r8 - r7)
+ {
+ r5 = r10 - r8 - r7;
+ }
+ }
+ if (r5 > 0)
+ {
+ r10 = r10 - r5;
+ }
+
+ r10 = r10 - (r7 + r8);
+ flags = flags & 0x8;
+ if (!flags)
+ {
+ string_fill_char(&str, (s8)unk.unk1C, r10);
+ }
+ s8 *x = &unk.unk38 + r7;
+ while (r7 > 0)
+ {
+ s8 ch = *(x--);
+ r7--;
+ string_put_char(&str, ch);
+ }
+ string_fill_char(&str, (s8)unk.unk20, r5);
+ x = &unk.unk3A + r8;
+ while (r8 > 0)
+ {
+ s8 ch = *(x--);
+ r8--;
+ string_put_char(&str, ch);
+ }
+ if (flags)
+ {
+ string_fill_char(&str, (s8)unk.unk1C, r10);
+ }
+ }
+ }
+ format++;
+ break;
+ }
+ if (str.spaceLeft != 0)
+ {
+ *str.stringEnd = 0;
+ }
+ else if (unk.unk00 != 0)
+ {
+ *(str.stringStart + unk.unk00 - 1) = 0;
+ }
+ }
+ } while (*format != 0);
+ }
+
+ if (str.spaceLeft != 0)
+ {
+ *str.stringEnd = 0;
+ }
+ else if (unk.unk00 != 0)
+ {
+ str.stringStart[unk.unk00] = 0;
+ }
+ return str.stringEnd - str.stringStart;
+}
+
+#endif
diff --git a/arm9/lib/src/OS_reset.c b/arm9/lib/src/OS_reset.c
new file mode 100644
index 00000000..c21d20ab
--- /dev/null
+++ b/arm9/lib/src/OS_reset.c
@@ -0,0 +1,62 @@
+//
+// Created by red031000 on 2020-05-06.
+//
+
+#include "function_target.h"
+#include "OS_reset.h"
+#include "MB_mb.h"
+#include "OS_terminate_proc.h"
+
+extern u16 OSi_IsInitReset;
+extern vu16 OSi_IsResetOccurred;
+extern void PXI_Init();
+extern u32 PXI_IsCallbackReady(u32 param1, u32 param2);
+extern void PXI_SetFifoRecvCallback(u32 param1, void* callback);
+extern u32 PXI_SendWordByFifo(u32 param1, u32 data, u32 param2);
+extern void CARD_LockRom(u16 lockId);
+extern void MI_StopDma(u32 dma);
+extern void OS_SetIrqMask(u32 mask);
+extern void OS_ResetRequestIrqMask(u32 mask);
+extern void OSi_DoResetSystem(); //in itcm, should technically be in this file
+
+ARM_FUNC void OS_InitReset() {
+ if (OSi_IsInitReset) {
+ return;
+ }
+ OSi_IsInitReset = TRUE;
+ PXI_Init();
+ while (!PXI_IsCallbackReady(PXI_FIFO_TAG_OS, PXI_PROC_ARM7)) { }
+
+ PXI_SetFifoRecvCallback(PXI_FIFO_TAG_OS, OSi_CommonCallback);
+}
+
+ARM_FUNC static void OSi_CommonCallback(PXIFifoTag tag, u32 data, BOOL err) {
+#pragma unused(tag, err) //needed because otherwise -W all errors
+ u16 command = (u16)((data & OS_PXI_COMMAND_MASK) >> OS_PXI_COMMAND_SHIFT);
+ if (command == OS_PXI_COMMAND_RESET)
+ {
+ OSi_IsResetOccurred = TRUE;
+ return;
+ }
+ OS_Terminate();
+}
+
+ARM_FUNC static void OSi_SendToPxi(u16 data) {
+ while (PXI_SendWordByFifo(PXI_FIFO_TAG_OS, (u32)data << 0x8, FALSE)) {}
+}
+
+ARM_FUNC void OS_ResetSystem(u32 parameter) {
+ if (MB_IsMultiBootChild()) {
+ OS_Terminate();
+ }
+ CARD_LockRom((u16)OS_GetLockID());
+ MI_StopDma(0);
+ MI_StopDma(1);
+ MI_StopDma(2);
+ MI_StopDma(3);
+ OS_SetIrqMask(0x40000);
+ OS_ResetRequestIrqMask((u32)~0);
+ *(u32 *)HW_RESET_PARAMETER_BUF = parameter;
+ OSi_SendToPxi(OS_PXI_COMMAND_RESET);
+ OSi_DoResetSystem(); //oh boy this is in itcm, that's gonna be fun to deal with Kappa
+}
diff --git a/arm9/lib/src/OS_system.c b/arm9/lib/src/OS_system.c
index c2b08681..e5dfcb47 100644
--- a/arm9/lib/src/OS_system.c
+++ b/arm9/lib/src/OS_system.c
@@ -2,7 +2,6 @@
// Created by mart on 4/23/20.
//
-#include "function_target.h"
#include "OS_system.h"
ARM_FUNC asm OSIntrMode OS_EnableInterrupts() {
diff --git a/arm9/lib/src/OS_tcm.c b/arm9/lib/src/OS_tcm.c
new file mode 100644
index 00000000..5a168c58
--- /dev/null
+++ b/arm9/lib/src/OS_tcm.c
@@ -0,0 +1,13 @@
+//
+// Created by red031000 on 2020-05-05.
+//
+
+#include "OS_tcm.h"
+#include "function_target.h"
+
+ARM_FUNC asm u32 OS_GetDTCMAddress() {
+ mrc p15, 0x0, r0, c9, c1, 0x0
+ ldr r1, =OSi_TCM_REGION_BASE_MASK
+ and r0, r0, r1
+ bx lr
+}
diff --git a/arm9/lib/src/OS_terminate_proc.c b/arm9/lib/src/OS_terminate_proc.c
new file mode 100644
index 00000000..eb267c6b
--- /dev/null
+++ b/arm9/lib/src/OS_terminate_proc.c
@@ -0,0 +1,21 @@
+//
+// Created by red031000 on 2020-05-07.
+//
+
+#include "types.h"
+#include "OS_terminate_proc.h"
+#include "function_target.h"
+#include "OS_system.h"
+
+ARM_FUNC void OS_Terminate() {
+ while (TRUE) {
+ (void)OS_DisableInterrupts();
+ OS_Halt();
+ }
+}
+
+ARM_FUNC asm void OS_Halt() {
+ mov r0, #0x0
+ mcr p15, 0x0, r0, c7, c0, 0x4
+ bx lr
+}