summaryrefslogtreecommitdiff
path: root/arm9
diff options
context:
space:
mode:
Diffstat (limited to 'arm9')
-rw-r--r--arm9/Makefile2
-rw-r--r--arm9/arm9.lsf1
-rw-r--r--arm9/asm/NNS_FND_allocator.s65
-rw-r--r--arm9/asm/NNS_FND_expheap.s583
-rw-r--r--arm9/asm/NNS_FND_expheap_s.s159
-rw-r--r--arm9/asm/NNS_FND_heapcommon.s112
-rw-r--r--arm9/asm/NNS_FND_list.s169
-rw-r--r--arm9/lib/libnns/include/NNS_FND_expheap.h4
-rw-r--r--arm9/lib/libnns/include/NNS_FND_heapcommon.h85
-rw-r--r--arm9/lib/libnns/include/NNS_FND_list.h15
-rw-r--r--arm9/lib/libnns/src/NNS_FND_allocator.c32
-rw-r--r--arm9/lib/libnns/src/NNS_FND_expheap.c385
-rw-r--r--arm9/lib/libnns/src/NNS_FND_heapcommon.c55
-rw-r--r--arm9/lib/libnns/src/NNS_FND_list.c128
14 files changed, 864 insertions, 931 deletions
diff --git a/arm9/Makefile b/arm9/Makefile
index b48ac56c..e3c573b7 100644
--- a/arm9/Makefile
+++ b/arm9/Makefile
@@ -194,6 +194,8 @@ ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(LIB
$(BUILD_DIR)/lib/%.o: MWCCVERSION = 1.2/sp2p3
$(BUILD_DIR)/lib/%.o: CFLAGS = -O4,p -gccext,on -proc arm946e -fp soft -lang c99 -Cpp_exceptions off -interworking -DFS_IMPLEMENT -enum int -W all -i ../include -ir ../include-mw -ir lib/libc/include -ir lib/libnns/include -ir lib/NitroSDK/include
+$(BUILD_DIR)/lib/libnns/%.o: MWCCVERSION = 1.2/sp3
+
# FIXME: Using -ipa file breaks .rodata alignment
$(BUILD_DIR)/src/math_util.o: CFLAGS = -O4,p -gccext,on -proc arm946e -fp soft -lang c99 -Cpp_exceptions off $(foreach dir,$(INCLUDE_DIRS),-i $(dir)) $(foreach dir,$(INCLUDE_RECURSIVE_DIRS),-ir $(dir)) -interworking -DFS_IMPLEMENT -enum int -W all -D$(GAME_VERSION) -D$(GAME_LANGUAGE)
diff --git a/arm9/arm9.lsf b/arm9/arm9.lsf
index 04756a55..78e3e725 100644
--- a/arm9/arm9.lsf
+++ b/arm9/arm9.lsf
@@ -358,6 +358,7 @@ Static arm9
### Nitro System SDK ###
Object NNS_FND_list.o
Object NNS_FND_heapcommon.o
+ Object NNS_FND_expheap_s.o
Object NNS_FND_expheap.o
Object NNS_FND_frameheap.o
Object NNS_FND_allocator.o
diff --git a/arm9/asm/NNS_FND_allocator.s b/arm9/asm/NNS_FND_allocator.s
deleted file mode 100644
index 537ce6a0..00000000
--- a/arm9/asm/NNS_FND_allocator.s
+++ /dev/null
@@ -1,65 +0,0 @@
- .include "asm/macros.inc"
- .include "global.inc"
- .rodata
- ; static const in function
-
- .global sAllocatorFunc$7864
-sAllocatorFunc$7864: ; 0x020FF7CC
- .word AllocatorAllocForExpHeap
- .word AllocatorFreeForExpHeap
- .text
-
- arm_func_start NNS_FndInitAllocatorForExpHeap
-NNS_FndInitAllocatorForExpHeap: ; 0x020AE82C
- ldr ip, _020AE848 ; =sAllocatorFunc$7864
- mov r3, #0x0
- str r12, [r0, #0x0]
- str r1, [r0, #0x4]
- str r2, [r0, #0x8]
- str r3, [r0, #0xc]
- bx lr
- .balign 4
-_020AE848: .word sAllocatorFunc$7864
- arm_func_end NNS_FndInitAllocatorForExpHeap
-
- arm_func_start NNS_FndFreeToAllocator
-NNS_FndFreeToAllocator: ; 0x020AE84C
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- ldr r2, [r0, #0x0]
- ldr r2, [r2, #0x4]
- blx r2
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndFreeToAllocator
-
- arm_func_start NNS_FndAllocFromAllocator
-NNS_FndAllocFromAllocator: ; 0x020AE868
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- ldr r2, [r0, #0x0]
- ldr r2, [r2, #0x0]
- blx r2
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndAllocFromAllocator
-
- arm_func_start AllocatorFreeForExpHeap
-AllocatorFreeForExpHeap: ; 0x020AE884
- ldr ip, _020AE890 ; =NNS_FndFreeToExpHeap
- ldr r0, [r0, #0x4]
- bx r12
- .balign 4
-_020AE890: .word NNS_FndFreeToExpHeap
- arm_func_end AllocatorFreeForExpHeap
-
- arm_func_start AllocatorAllocForExpHeap
-AllocatorAllocForExpHeap: ; 0x020AE894
- ldr ip, _020AE8A8 ; =NNS_FndAllocFromExpHeapEx
- mov r2, r0
- ldr r0, [r2, #0x4]
- ldr r2, [r2, #0x8]
- bx r12
- .balign 4
-_020AE8A8: .word NNS_FndAllocFromExpHeapEx
- arm_func_end AllocatorAllocForExpHeap
diff --git a/arm9/asm/NNS_FND_expheap.s b/arm9/asm/NNS_FND_expheap.s
deleted file mode 100644
index e94dba38..00000000
--- a/arm9/asm/NNS_FND_expheap.s
+++ /dev/null
@@ -1,583 +0,0 @@
- .include "asm/macros.inc"
- .include "global.inc"
- .extern NNSi_FndInitHeapHead
- .extern NNSi_FndFinalizeHeap
- .text
-
- arm_func_start NNS_FndGetSizeForMBlockExpHeap
-NNS_FndGetSizeForMBlockExpHeap: ; 0x020ADDC0
- ldr r0, [r0, #-0xc]
- bx lr
- arm_func_end NNS_FndGetSizeForMBlockExpHeap
-
- arm_func_start NNS_FndGetTotalFreeSizeForExpHeap
-NNS_FndGetTotalFreeSizeForExpHeap: ; 0x020ADDC8
- ldr r2, [r0, #0x24]
- mov r0, #0x0
- cmp r2, #0x0
- bxeq lr
-_020ADDD8:
- ldr r1, [r2, #0x4]
- ldr r2, [r2, #0xc]
- add r0, r0, r1
- cmp r2, #0x0
- bne _020ADDD8
- bx lr
- arm_func_end NNS_FndGetTotalFreeSizeForExpHeap
-
- arm_func_start NNS_FndFreeToExpHeap
-NNS_FndFreeToExpHeap: ; 0x020ADDF0
- stmdb sp!, {r4-r5,lr}
- sub sp, sp, #0xc
- sub r4, r1, #0x10
- add r5, r0, #0x24
- add r0, sp, #0x0
- mov r1, r4
- bl GetRegionOfMBlock
- mov r1, r4
- add r0, r5, #0x8
- bl RemoveMBlock
- add r1, sp, #0x0
- mov r0, r5
- bl RecycleRegion
- add sp, sp, #0xc
- ldmia sp!, {r4-r5,pc}
- arm_func_end NNS_FndFreeToExpHeap
-
- arm_func_start NNS_FndResizeForMBlockExpHeap
-NNS_FndResizeForMBlockExpHeap: ; 0x020ADE2C
- stmdb sp!, {r4-r10,lr}
- sub sp, sp, #0x10
- mov r4, r1
- mov r10, r2
- sub r6, r4, #0x10
- add r1, r10, #0x3
- mov r5, r0
- ldr r8, [r6, #0x4]
- bic r10, r1, #0x3
- cmp r10, r8
- add r7, r5, #0x24
- addeq sp, sp, #0x10
- moveq r0, r10
- ldmeqia sp!, {r4-r10,pc}
- cmp r10, r8
- bls _020ADF60
- ldr r9, [r7, #0x0]
- add r0, r6, #0x10
- cmp r9, #0x0
- add r0, r8, r0
- beq _020ADE94
-_020ADE80:
- cmp r9, r0
- beq _020ADE94
- ldr r9, [r9, #0xc]
- cmp r9, #0x0
- bne _020ADE80
-_020ADE94:
- cmp r9, #0x0
- beq _020ADEB0
- ldr r0, [r9, #0x4]
- add r1, r8, #0x10
- add r0, r1, r0
- cmp r10, r0
- bls _020ADEBC
-_020ADEB0:
- add sp, sp, #0x10
- mov r0, #0x0
- ldmia sp!, {r4-r10,pc}
-_020ADEBC:
- add r0, sp, #0x0
- mov r1, r9
- bl GetRegionOfMBlock
- mov r0, r7
- mov r1, r9
- bl RemoveMBlock
- ldr r2, [sp, #0x4]
- add r3, r10, r4
- ldr r9, [sp, #0x0]
- sub r1, r2, r3
- str r3, [sp, #0x0]
- cmp r1, #0x10
- strcc r2, [sp, #0x0]
- mov r8, r0
- ldr r0, [sp, #0x0]
- sub r0, r0, r4
- str r0, [r6, #0x4]
- ldr r1, [sp, #0x4]
- ldr r0, [sp, #0x0]
- sub r0, r1, r0
- cmp r0, #0x10
- blo _020ADF30
- ldr r1, _020ADF9C ; =0x00004652
- add r0, sp, #0x0
- bl InitMBlock
- mov r1, r0
- mov r0, r7
- mov r2, r8
- bl InsertMBlock
-_020ADF30:
- ldr r0, [r5, #0x20]
- ldr r1, [sp, #0x0]
- and r0, r0, #0xff
- mov r0, r0, lsl #0x10
- mov r0, r0, lsr #0x10
- sub r2, r1, r9
- ands r0, r0, #0x1
- beq _020ADF90
- mov r1, r9
- mov r0, #0x0
- bl MIi_CpuClear32
- b _020ADF90
-_020ADF60:
- add r0, r10, r4
- str r0, [sp, #0x8]
- ldr r1, [r6, #0x4]
- add r0, r6, #0x10
- add r0, r1, r0
- str r0, [sp, #0xc]
- add r1, sp, #0x8
- mov r0, r7
- str r10, [r6, #0x4]
- bl RecycleRegion
- cmp r0, #0x0
- streq r8, [r6, #0x4]
-_020ADF90:
- ldr r0, [r6, #0x4]
- add sp, sp, #0x10
- ldmia sp!, {r4-r10,pc}
- .balign 4
-_020ADF9C: .word 0x00004652
- arm_func_end NNS_FndResizeForMBlockExpHeap
-
- arm_func_start NNS_FndAllocFromExpHeapEx
-NNS_FndAllocFromExpHeapEx: ; 0x020ADFA0
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- cmp r1, #0x0
- moveq r1, #0x1
- add r1, r1, #0x3
- cmp r2, #0x0
- bic r1, r1, #0x3
- blt _020ADFCC
- bl AllocFromHead
- add sp, sp, #0x4
- ldmia sp!, {pc}
-_020ADFCC:
- rsb r2, r2, #0x0
- bl AllocFromTail
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndAllocFromExpHeapEx
-
- arm_func_start NNS_FndDestroyExpHeap
-NNS_FndDestroyExpHeap: ; 0x020ADFDC
- ldr ip, _020ADFE4 ; =NNSi_FndFinalizeHeap
- bx r12
- .balign 4
-_020ADFE4: .word NNSi_FndFinalizeHeap
- arm_func_end NNS_FndDestroyExpHeap
-
- arm_func_start NNS_FndCreateExpHeapEx
-NNS_FndCreateExpHeapEx: ; 0x020ADFE8
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- add r1, r1, r0
- add r0, r0, #0x3
- bic r1, r1, #0x3
- bic r0, r0, #0x3
- cmp r0, r1
- bhi _020AE014
- sub r3, r1, r0
- cmp r3, #0x4c
- bhs _020AE020
-_020AE014:
- add sp, sp, #0x4
- mov r0, #0x0
- ldmia sp!, {pc}
-_020AE020:
- bl InitExpHeap
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndCreateExpHeapEx
-
- arm_func_start RecycleRegion
-RecycleRegion:
- stmdb sp!, {r4-r6,lr}
- sub sp, sp, #0x8
- mov r5, r1
- ldr r2, [r5, #0x0]
- ldr r1, [r5, #0x4]
- mov r6, r0
- str r2, [sp, #0x0]
- str r1, [sp, #0x4]
- ldr r1, [r6, #0x0]
- mov r4, #0x0
- cmp r1, #0x0
- beq _020AE0A0
- ldr r0, [r5, #0x0]
-_020AE060:
- cmp r1, r0
- movcc r4, r1
- blo _020AE094
- ldr r0, [r5, #0x4]
- cmp r1, r0
- bne _020AE0A0
- ldr r2, [r1, #0x4]
- add r0, r1, #0x10
- add r2, r2, r0
- mov r0, r6
- str r2, [sp, #0x4]
- bl RemoveMBlock
- b _020AE0A0
-_020AE094:
- ldr r1, [r1, #0xc]
- cmp r1, #0x0
- bne _020AE060
-_020AE0A0:
- cmp r4, #0x0
- beq _020AE0D4
- ldr r2, [r4, #0x4]
- add r1, r4, #0x10
- ldr r0, [r5, #0x0]
- add r1, r2, r1
- cmp r1, r0
- bne _020AE0D4
- mov r0, r6
- mov r1, r4
- str r4, [sp, #0x0]
- bl RemoveMBlock
- mov r4, r0
-_020AE0D4:
- ldr r1, [sp, #0x4]
- ldr r0, [sp, #0x0]
- sub r0, r1, r0
- cmp r0, #0x10
- addcc sp, sp, #0x8
- movcc r0, #0x0
- ldmccia sp!, {r4-r6,pc}
- ldr r1, _020AE118 ; =0x00004652
- add r0, sp, #0x0
- bl InitMBlock
- mov r1, r0
- mov r0, r6
- mov r2, r4
- bl InsertMBlock
- mov r0, #0x1
- add sp, sp, #0x8
- ldmia sp!, {r4-r6,pc}
- .balign 4
-_020AE118: .word 0x00004652
- arm_func_end RecycleRegion
-
- local_arm_func_start AllocFromTail
-AllocFromTail: ; 0x020AE11C
- stmdb sp!, {r4-r9,lr}
- sub sp, sp, #0x4
- add r0, r0, #0x24
- ldrh r4, [r0, #0x12]
- mov r3, r1
- mvn lr, #0x0
- and r1, r4, #0x1
- mov r1, r1, lsl #0x10
- movs r1, r1, lsr #0x10
- moveq r5, #0x1
- mov r1, #0x0
- ldr r4, [r0, #0x4]
- movne r5, #0x0
- mov r12, r1
- cmp r4, #0x0
- beq _020AE1B0
- sub r2, r2, #0x1
- mvn r2, r2
-_020AE164:
- ldr r8, [r4, #0x4]
- add r9, r4, #0x10
- add r6, r8, r9
- sub r6, r6, r3
- and r7, r2, r6
- subs r6, r7, r9
- bmi _020AE1A4
- cmp lr, r8
- bls _020AE1A4
- mov r1, r4
- mov lr, r8
- mov r12, r7
- cmp r5, #0x0
- bne _020AE1B0
- cmp r8, r3
- beq _020AE1B0
-_020AE1A4:
- ldr r4, [r4, #0x8]
- cmp r4, #0x0
- bne _020AE164
-_020AE1B0:
- cmp r1, #0x0
- addeq sp, sp, #0x4
- moveq r0, #0x0
- ldmeqia sp!, {r4-r9,pc}
- mov r4, #0x1
- mov r2, r12
- str r4, [sp, #0x0]
- bl AllocUsedBlockFromFreeBlock
- add sp, sp, #0x4
- ldmia sp!, {r4-r9,pc}
- arm_func_end AllocFromTail
-
- local_arm_func_start AllocFromHead
-AllocFromHead: ; 0x020AE1D8
- stmdb sp!, {r4-r9,lr}
- sub sp, sp, #0x4
- add r0, r0, #0x24
- ldrh r4, [r0, #0x12]
- mov r3, r1
- ldr r5, [r0, #0x0]
- and r1, r4, #0x1
- mov r1, r1, lsl #0x10
- movs r1, r1, lsr #0x10
- moveq r6, #0x1
- mov r1, #0x0
- movne r6, #0x0
- mov lr, r1
- cmp r5, #0x0
- mvn r4, #0x0
- beq _020AE270
- sub r12, r2, #0x1
- mvn r2, r12
-_020AE220:
- add r8, r5, #0x10
- add r7, r12, r8
- and r9, r2, r7
- sub r7, r9, r8
- ldr r8, [r5, #0x4]
- add r7, r3, r7
- cmp r8, r7
- blo _020AE264
- cmp r4, r8
- bls _020AE264
- mov r1, r5
- mov r4, r8
- mov lr, r9
- cmp r6, #0x0
- bne _020AE270
- cmp r8, r3
- beq _020AE270
-_020AE264:
- ldr r5, [r5, #0xc]
- cmp r5, #0x0
- bne _020AE220
-_020AE270:
- cmp r1, #0x0
- addeq sp, sp, #0x4
- moveq r0, #0x0
- ldmeqia sp!, {r4-r9,pc}
- mov r4, #0x0
- mov r2, lr
- str r4, [sp, #0x0]
- bl AllocUsedBlockFromFreeBlock
- add sp, sp, #0x4
- ldmia sp!, {r4-r9,pc}
- arm_func_end AllocFromHead
-
- arm_func_start AllocUsedBlockFromFreeBlock
-AllocUsedBlockFromFreeBlock: ; 0x020AE298
- stmdb sp!, {r4-r8,lr}
- sub sp, sp, #0x18
- mov r7, r0
- add r0, sp, #0x0
- mov r8, r1
- mov r6, r2
- mov r5, r3
- bl GetRegionOfMBlock
- ldr r3, [sp, #0x4]
- sub r4, r6, #0x10
- add r2, r5, r6
- mov r0, r7
- mov r1, r8
- str r4, [sp, #0x4]
- str r3, [sp, #0xc]
- str r2, [sp, #0x8]
- bl RemoveMBlock
- ldr r2, [sp, #0x0]
- ldr r1, [sp, #0x4]
- mov r5, r0
- sub r0, r1, r2
- cmp r0, #0x10
- strcc r2, [sp, #0x4]
- blo _020AE318
- ldr r1, _020AE418 ; =0x00004652
- add r0, sp, #0x0
- bl InitMBlock
- mov r1, r0
- mov r0, r7
- mov r2, r5
- bl InsertMBlock
- mov r5, r0
-_020AE318:
- ldr r1, [sp, #0xc]
- ldr r0, [sp, #0x8]
- sub r0, r1, r0
- cmp r0, #0x10
- strcc r1, [sp, #0x8]
- blo _020AE34C
- ldr r1, _020AE418 ; =0x00004652
- add r0, sp, #0x8
- bl InitMBlock
- mov r1, r0
- mov r0, r7
- mov r2, r5
- bl InsertMBlock
-_020AE34C:
- ldr r0, [r7, #-0x4]
- ldr r1, [sp, #0x4]
- and r0, r0, #0xff
- mov r0, r0, lsl #0x10
- ldr r2, [sp, #0x8]
- mov r0, r0, lsr #0x10
- sub r2, r2, r1
- ands r0, r0, #0x1
- beq _020AE378
- mov r0, #0x0
- bl MIi_CpuClear32
-_020AE378:
- ldr r2, [sp, #0x8]
- ldr r1, _020AE41C ; =0x00005544
- add r0, sp, #0x10
- str r4, [sp, #0x10]
- str r2, [sp, #0x14]
- bl InitMBlock
- mov r1, r0
- ldrh r3, [r1, #0x2]
- ldrh r2, [sp, #0x30]
- add r0, r7, #0x8
- bic r3, r3, #0x8000
- strh r3, [r1, #0x2]
- ldrh r3, [r1, #0x2]
- and r2, r2, #0x1
- orr r2, r3, r2, lsl #0xf
- strh r2, [r1, #0x2]
- ldrh r2, [r1, #0x2]
- ldr r3, [sp, #0x4]
- bic r2, r2, #0x7f00
- strh r2, [r1, #0x2]
- sub r2, r1, r3
- mov r2, r2, lsl #0x10
- mov r2, r2, lsr #0x10
- ldrh r3, [r1, #0x2]
- and r2, r2, #0x7f
- orr r2, r3, r2, lsl #0x8
- strh r2, [r1, #0x2]
- ldrh r2, [r1, #0x2]
- ldrh r3, [r7, #0x10]
- bic r2, r2, #0xff
- strh r2, [r1, #0x2]
- ldrh r2, [r1, #0x2]
- and r3, r3, #0xff
- orr r2, r2, r3
- strh r2, [r1, #0x2]
- ldr r2, [r7, #0xc]
- bl InsertMBlock
- mov r0, r6
- add sp, sp, #0x18
- ldmia sp!, {r4-r8,pc}
- .balign 4
-_020AE418: .word 0x00004652
-_020AE41C: .word 0x00005544
- arm_func_end AllocUsedBlockFromFreeBlock
-
- arm_func_start InitExpHeap
-InitExpHeap: ; 0x020AE420
- stmdb sp!, {r4-r5,lr}
- sub sp, sp, #0xc
- mov r5, r0
- mov r3, r1
- add r4, r5, #0x24
- str r2, [sp, #0x0]
- ldr r1, _020AE498 ; =0x45585048
- add r2, r4, #0x14
- bl NNSi_FndInitHeapHead
- mov r0, #0x0
- strh r0, [r4, #0x10]
- strh r0, [r4, #0x12]
- ldrh r2, [r4, #0x12]
- ldr r1, _020AE49C ; =0x00004652
- add r0, sp, #0x4
- bic r2, r2, #0x1
- strh r2, [r4, #0x12]
- ldr r2, [r5, #0x18]
- str r2, [sp, #0x4]
- ldr r2, [r5, #0x1c]
- str r2, [sp, #0x8]
- bl InitMBlock
- str r0, [r5, #0x24]
- str r0, [r4, #0x4]
- mov r1, #0x0
- str r1, [r4, #0x8]
- mov r0, r5
- str r1, [r4, #0xc]
- add sp, sp, #0xc
- ldmia sp!, {r4-r5,pc}
- .balign 4
-_020AE498: .word 0x45585048
-_020AE49C: .word 0x00004652
- arm_func_end InitExpHeap
-
- arm_func_start InitMBlock
-InitMBlock: ; 0x020AE4A0
- ldr r3, [r0, #0x0]
- mov r2, #0x0
- strh r1, [r3, #0x0]
- strh r2, [r3, #0x2]
- ldr r1, [r0, #0x4]
- add r0, r3, #0x10
- sub r0, r1, r0
- str r0, [r3, #0x4]
- str r2, [r3, #0x8]
- mov r0, r3
- str r2, [r3, #0xc]
- bx lr
- arm_func_end InitMBlock
-
- arm_func_start InsertMBlock
-InsertMBlock: ; 0x020AE4D0
- str r2, [r1, #0x8]
- cmp r2, #0x0
- ldrne r3, [r2, #0xc]
- strne r1, [r2, #0xc]
- ldreq r3, [r0, #0x0]
- streq r1, [r0, #0x0]
- str r3, [r1, #0xc]
- cmp r3, #0x0
- strne r1, [r3, #0x8]
- streq r1, [r0, #0x4]
- mov r0, r1
- bx lr
- arm_func_end InsertMBlock
-
- arm_func_start RemoveMBlock
-RemoveMBlock: ; 0x020AE500
- ldr r2, [r1, #0x8]
- ldr r1, [r1, #0xc]
- cmp r2, #0x0
- strne r1, [r2, #0xc]
- streq r1, [r0, #0x0]
- cmp r1, #0x0
- strne r2, [r1, #0x8]
- streq r2, [r0, #0x4]
- mov r0, r2
- bx lr
- arm_func_end RemoveMBlock
-
- arm_func_start GetRegionOfMBlock
-GetRegionOfMBlock: ; 0x020AE528
- ldrh r2, [r1, #0x2]
- add r3, r1, #0x10
- mov r2, r2, asr #0x8
- and r2, r2, #0x7f
- mov r2, r2, lsl #0x10
- sub r2, r1, r2, lsr #0x10
- str r2, [r0, #0x0]
- ldr r1, [r1, #0x4]
- add r1, r1, r3
- str r1, [r0, #0x4]
- bx lr
- arm_func_end GetRegionOfMBlock
diff --git a/arm9/asm/NNS_FND_expheap_s.s b/arm9/asm/NNS_FND_expheap_s.s
new file mode 100644
index 00000000..d4d958db
--- /dev/null
+++ b/arm9/asm/NNS_FND_expheap_s.s
@@ -0,0 +1,159 @@
+ .include "asm/macros.inc"
+ .include "global.inc"
+ .extern NNSi_FndInitHeapHead
+ .extern NNSi_FndFinalizeHeap
+ .extern GetRegionOfMBlock
+ .extern RemoveMBlock
+ .extern InsertMBlock
+ .extern InitMBlock
+ .extern InitExpHeap
+ .extern AllocUsedBlockFromFreeBlock
+ .extern AllocFromHead
+ .extern AllocFromTail
+ .extern RecycleRegion
+ .text
+
+ arm_func_start NNS_FndGetSizeForMBlockExpHeap
+NNS_FndGetSizeForMBlockExpHeap: ; 0x020ADDC0
+ ldr r0, [r0, #-0xc]
+ bx lr
+ arm_func_end NNS_FndGetSizeForMBlockExpHeap
+
+ arm_func_start NNS_FndGetTotalFreeSizeForExpHeap
+NNS_FndGetTotalFreeSizeForExpHeap: ; 0x020ADDC8
+ ldr r2, [r0, #0x24]
+ mov r0, #0x0
+ cmp r2, #0x0
+ bxeq lr
+_020ADDD8:
+ ldr r1, [r2, #0x4]
+ ldr r2, [r2, #0xc]
+ add r0, r0, r1
+ cmp r2, #0x0
+ bne _020ADDD8
+ bx lr
+ arm_func_end NNS_FndGetTotalFreeSizeForExpHeap
+
+ arm_func_start NNS_FndFreeToExpHeap
+NNS_FndFreeToExpHeap: ; 0x020ADDF0
+ stmdb sp!, {r4-r5,lr}
+ sub sp, sp, #0xc
+ sub r4, r1, #0x10
+ add r5, r0, #0x24
+ add r0, sp, #0x0
+ mov r1, r4
+ bl GetRegionOfMBlock
+ mov r1, r4
+ add r0, r5, #0x8
+ bl RemoveMBlock
+ add r1, sp, #0x0
+ mov r0, r5
+ bl RecycleRegion
+ add sp, sp, #0xc
+ ldmia sp!, {r4-r5,pc}
+ arm_func_end NNS_FndFreeToExpHeap
+
+ arm_func_start NNS_FndResizeForMBlockExpHeap
+NNS_FndResizeForMBlockExpHeap: ; 0x020ADE2C
+ stmdb sp!, {r4-r10,lr}
+ sub sp, sp, #0x10
+ mov r4, r1
+ mov r10, r2
+ sub r6, r4, #0x10
+ add r1, r10, #0x3
+ mov r5, r0
+ ldr r8, [r6, #0x4]
+ bic r10, r1, #0x3
+ cmp r10, r8
+ add r7, r5, #0x24
+ addeq sp, sp, #0x10
+ moveq r0, r10
+ ldmeqia sp!, {r4-r10,pc}
+ cmp r10, r8
+ bls _020ADF60
+ ldr r9, [r7, #0x0]
+ add r0, r6, #0x10
+ cmp r9, #0x0
+ add r0, r8, r0
+ beq _020ADE94
+_020ADE80:
+ cmp r9, r0
+ beq _020ADE94
+ ldr r9, [r9, #0xc]
+ cmp r9, #0x0
+ bne _020ADE80
+_020ADE94:
+ cmp r9, #0x0
+ beq _020ADEB0
+ ldr r0, [r9, #0x4]
+ add r1, r8, #0x10
+ add r0, r1, r0
+ cmp r10, r0
+ bls _020ADEBC
+_020ADEB0:
+ add sp, sp, #0x10
+ mov r0, #0x0
+ ldmia sp!, {r4-r10,pc}
+_020ADEBC:
+ add r0, sp, #0x0
+ mov r1, r9
+ bl GetRegionOfMBlock
+ mov r0, r7
+ mov r1, r9
+ bl RemoveMBlock
+ ldr r2, [sp, #0x4]
+ add r3, r10, r4
+ ldr r9, [sp, #0x0]
+ sub r1, r2, r3
+ str r3, [sp, #0x0]
+ cmp r1, #0x10
+ strcc r2, [sp, #0x0]
+ mov r8, r0
+ ldr r0, [sp, #0x0]
+ sub r0, r0, r4
+ str r0, [r6, #0x4]
+ ldr r1, [sp, #0x4]
+ ldr r0, [sp, #0x0]
+ sub r0, r1, r0
+ cmp r0, #0x10
+ blo _020ADF30
+ ldr r1, _020ADF9C ; =0x00004652
+ add r0, sp, #0x0
+ bl InitMBlock
+ mov r1, r0
+ mov r0, r7
+ mov r2, r8
+ bl InsertMBlock
+_020ADF30:
+ ldr r0, [r5, #0x20]
+ ldr r1, [sp, #0x0]
+ and r0, r0, #0xff
+ mov r0, r0, lsl #0x10
+ mov r0, r0, lsr #0x10
+ sub r2, r1, r9
+ ands r0, r0, #0x1
+ beq _020ADF90
+ mov r1, r9
+ mov r0, #0x0
+ bl MIi_CpuClear32
+ b _020ADF90
+_020ADF60:
+ add r0, r10, r4
+ str r0, [sp, #0x8]
+ ldr r1, [r6, #0x4]
+ add r0, r6, #0x10
+ add r0, r1, r0
+ str r0, [sp, #0xc]
+ add r1, sp, #0x8
+ mov r0, r7
+ str r10, [r6, #0x4]
+ bl RecycleRegion
+ cmp r0, #0x0
+ streq r8, [r6, #0x4]
+_020ADF90:
+ ldr r0, [r6, #0x4]
+ add sp, sp, #0x10
+ ldmia sp!, {r4-r10,pc}
+ .balign 4
+_020ADF9C: .word 0x00004652
+ arm_func_end NNS_FndResizeForMBlockExpHeap
diff --git a/arm9/asm/NNS_FND_heapcommon.s b/arm9/asm/NNS_FND_heapcommon.s
deleted file mode 100644
index ca3108d2..00000000
--- a/arm9/asm/NNS_FND_heapcommon.s
+++ /dev/null
@@ -1,112 +0,0 @@
- .include "asm/macros.inc"
- .include "global.inc"
-
- .section .bss
-
- .global sRootListInitialized
-sRootListInitialized: ; 0x021CCD38
- .space 0x4
-
- .global sRootList
-sRootList: ; 0x021CCD3C
- .space 0xc
- .text
-
- arm_func_start NNSi_FndFinalizeHeap
-NNSi_FndFinalizeHeap: ; 0x020ADC8C
- stmdb sp!, {r4,lr}
- mov r4, r0
- bl FindListContainHeap
- mov r1, r4
- bl NNS_FndRemoveListObject
- ldmia sp!, {r4,pc}
- arm_func_end NNSi_FndFinalizeHeap
-
- arm_func_start NNSi_FndInitHeapHead
-NNSi_FndInitHeapHead:
- stmdb sp!, {r4,lr}
- mov r4, r0
- str r1, [r4, #0x0]
- str r2, [r4, #0x18]
- str r3, [r4, #0x1c]
- mov r0, #0x0
- str r0, [r4, #0x20]
- ldr r1, [r4, #0x20]
- ldrh r0, [sp, #0x8]
- bic r1, r1, #0xff
- str r1, [r4, #0x20]
- ldr r1, [r4, #0x20]
- and r0, r0, #0xff
- orr r2, r1, r0
- add r0, r4, #0xc
- mov r1, #0x4
- str r2, [r4, #0x20]
- bl NNS_FndInitList
- ldr r0, _020ADD28 ; =sRootListInitialized
- ldr r0, [r0, #0x0]
- cmp r0, #0x0
- bne _020ADD14
- ldr r0, _020ADD2C ; =sRootList
- mov r1, #0x4
- bl NNS_FndInitList
- ldr r0, _020ADD28 ; =sRootListInitialized
- mov r1, #0x1
- str r1, [r0, #0x0]
-_020ADD14:
- mov r0, r4
- bl FindListContainHeap
- mov r1, r4
- bl NNS_FndAppendListObject
- ldmia sp!, {r4,pc}
- .balign 4
-_020ADD28: .word sRootListInitialized
-_020ADD2C: .word sRootList
- arm_func_end NNSi_FndInitHeapHead
-
- arm_func_start FindListContainHeap
-FindListContainHeap: ; 0x020ADD30
- stmdb sp!, {r4,lr}
- ldr r4, _020ADD54 ; =sRootList
- mov r1, r0
- mov r0, r4
- bl FindContainHeap
- cmp r0, #0x0
- addne r4, r0, #0xc
- mov r0, r4
- ldmia sp!, {r4,pc}
- .balign 4
-_020ADD54: .word sRootList
- arm_func_end FindListContainHeap
-
- arm_func_start FindContainHeap
-FindContainHeap:
- stmdb sp!, {r4-r6,lr}
- mov r5, r1
- mov r1, #0x0
- mov r6, r0
- bl NNS_FndGetNextListObject
- movs r4, r0
- beq _020ADDB8
-_020ADD74:
- ldr r0, [r4, #0x18]
- cmp r0, r5
- bhi _020ADDA4
- ldr r0, [r4, #0x1c]
- cmp r5, r0
- bhs _020ADDA4
- mov r1, r5
- add r0, r4, #0xc
- bl FindContainHeap
- cmp r0, #0x0
- moveq r0, r4
- ldmia sp!, {r4-r6,pc}
-_020ADDA4:
- mov r0, r6
- mov r1, r4
- bl NNS_FndGetNextListObject
- movs r4, r0
- bne _020ADD74
-_020ADDB8:
- mov r0, #0x0
- ldmia sp!, {r4-r6,pc}
- arm_func_end FindContainHeap
diff --git a/arm9/asm/NNS_FND_list.s b/arm9/asm/NNS_FND_list.s
deleted file mode 100644
index 21999c11..00000000
--- a/arm9/asm/NNS_FND_list.s
+++ /dev/null
@@ -1,169 +0,0 @@
- .include "asm/macros.inc"
- .include "global.inc"
- .text
-
- arm_func_start NNS_FndGetPrevListObject
-NNS_FndGetPrevListObject: ; 0x020ADA84
- cmp r1, #0x0
- ldreq r0, [r0, #0x4]
- ldrneh r0, [r0, #0xa]
- ldrne r0, [r1, r0]
- bx lr
- arm_func_end NNS_FndGetPrevListObject
-
- arm_func_start NNS_FndGetNextListObject
-NNS_FndGetNextListObject: ; 0x020ADA98
- cmp r1, #0x0
- ldreq r0, [r0, #0x0]
- ldrneh r0, [r0, #0xa]
- addne r0, r1, r0
- ldrne r0, [r0, #0x4]
- bx lr
- arm_func_end NNS_FndGetNextListObject
-
- arm_func_start NNS_FndRemoveListObject
-NNS_FndRemoveListObject: ; 0x020ADAB0
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- ldrh r12, [r0, #0xa]
- ldr r3, [r1, r12]
- add lr, r1, r12
- cmp r3, #0x0
- ldreq r1, [lr, #0x4]
- streq r1, [r0, #0x0]
- ldrne r2, [lr, #0x4]
- addne r1, r3, r12
- strne r2, [r1, #0x4]
- ldr r3, [lr, #0x4]
- cmp r3, #0x0
- ldreq r1, [lr, #0x0]
- streq r1, [r0, #0x4]
- ldrneh r1, [r0, #0xa]
- ldrne r2, [lr, #0x0]
- strne r2, [r3, r1]
- mov r1, #0x0
- str r1, [lr, #0x0]
- str r1, [lr, #0x4]
- ldrh r1, [r0, #0x8]
- sub r1, r1, #0x1
- strh r1, [r0, #0x8]
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndRemoveListObject
-
- arm_func_start NNS_FndInsertListObject
-NNS_FndInsertListObject: ; 0x020ADB18
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- cmp r1, #0x0
- bne _020ADB38
- mov r1, r2
- bl NNS_FndAppendListObject
- add sp, sp, #0x4
- ldmia sp!, {pc}
-_020ADB38:
- ldr r3, [r0, #0x0]
- cmp r1, r3
- bne _020ADB54
- mov r1, r2
- bl NNS_FndPrependListObject
- add sp, sp, #0x4
- ldmia sp!, {pc}
-_020ADB54:
- ldrh lr, [r0, #0xa]
- ldr r3, [r1, lr]
- add r12, r2, lr
- str r3, [r2, lr]
- str r1, [r12, #0x4]
- add r3, r3, lr
- str r2, [r3, #0x4]
- ldrh r3, [r0, #0xa]
- str r2, [r1, r3]
- ldrh r1, [r0, #0x8]
- add r1, r1, #0x1
- strh r1, [r0, #0x8]
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndInsertListObject
-
- arm_func_start NNS_FndPrependListObject
-NNS_FndPrependListObject: ; 0x020ADB8C
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- ldr r2, [r0, #0x0]
- cmp r2, #0x0
- bne _020ADBAC
- bl SetFirstObject
- add sp, sp, #0x4
- ldmia sp!, {pc}
-_020ADBAC:
- ldrh r3, [r0, #0xa]
- mov r2, #0x0
- str r2, [r1, r3]
- ldr r2, [r0, #0x0]
- add r3, r1, r3
- str r2, [r3, #0x4]
- ldrh r2, [r0, #0xa]
- ldr r3, [r0, #0x0]
- str r1, [r3, r2]
- str r1, [r0, #0x0]
- ldrh r1, [r0, #0x8]
- add r1, r1, #0x1
- strh r1, [r0, #0x8]
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndPrependListObject
-
- arm_func_start NNS_FndAppendListObject
-NNS_FndAppendListObject: ; 0x020ADBE8
- stmdb sp!, {lr}
- sub sp, sp, #0x4
- ldr r2, [r0, #0x0]
- cmp r2, #0x0
- bne _020ADC08
- bl SetFirstObject
- add sp, sp, #0x4
- ldmia sp!, {pc}
-_020ADC08:
- ldrh r12, [r0, #0xa]
- ldr r3, [r0, #0x4]
- mov r2, #0x0
- str r3, [r1, r12]
- add r3, r1, r12
- str r2, [r3, #0x4]
- ldrh r2, [r0, #0xa]
- ldr r3, [r0, #0x4]
- add r2, r3, r2
- str r1, [r2, #0x4]
- str r1, [r0, #0x4]
- ldrh r1, [r0, #0x8]
- add r1, r1, #0x1
- strh r1, [r0, #0x8]
- add sp, sp, #0x4
- ldmia sp!, {pc}
- arm_func_end NNS_FndAppendListObject
-
- arm_func_start SetFirstObject
-SetFirstObject: ; 0x020ADC48
- ldrh r3, [r0, #0xa]
- mov r2, #0x0
- add r12, r1, r3
- str r2, [r12, #0x4]
- str r2, [r1, r3]
- str r1, [r0, #0x0]
- str r1, [r0, #0x4]
- ldrh r1, [r0, #0x8]
- add r1, r1, #0x1
- strh r1, [r0, #0x8]
- bx lr
- arm_func_end SetFirstObject
-
- arm_func_start NNS_FndInitList
-NNS_FndInitList: ; 0x020ADC74
- mov r2, #0x0
- str r2, [r0, #0x0]
- str r2, [r0, #0x4]
- strh r2, [r0, #0x8]
- strh r1, [r0, #0xa]
- bx lr
- arm_func_end NNS_FndInitList
diff --git a/arm9/lib/libnns/include/NNS_FND_expheap.h b/arm9/lib/libnns/include/NNS_FND_expheap.h
index bdc3fcc4..acf33bd4 100644
--- a/arm9/lib/libnns/include/NNS_FND_expheap.h
+++ b/arm9/lib/libnns/include/NNS_FND_expheap.h
@@ -38,13 +38,13 @@ struct NNSiFndExpHeapHead
u16 feature; // Attribute
};
-NNSFndHeapHandle NNS_FndCreateExpHeapEx(void *startAddress, u32 size, u32 optFlag);
+NNSFndHeapHandle NNS_FndCreateExpHeapEx(void *startAddress, u32 size, u16 optFlag);
void *NNS_FndAllocFromExpHeapEx(NNSFndHeapHandle heap, u32 size, int alignment);
void NNS_FndDestroyExpHeap(NNSFndHeapHandle heap);
void NNS_FndFreeToExpHeap(NNSFndHeapHandle heap, void *memBlock);
u32 NNS_FndGetTotalFreeSizeForExpHeap(NNSFndHeapHandle heap);
u32 NNS_FndGetSizeForMBlockExpHeap(const void *memBlock);
-void NNS_FndResizeForMBlockExpHeap(NNSFndHeapHandle heap, void *memBlock, u32 size);
+u32 NNS_FndResizeForMBlockExpHeap(NNSFndHeapHandle heap, void *memBlock, u32 size);
#define NNS_FndCreateExpHeap(startAddress, size) \
NNS_FndCreateExpHeapEx(startAddress, size, 0)
diff --git a/arm9/lib/libnns/include/NNS_FND_heapcommon.h b/arm9/lib/libnns/include/NNS_FND_heapcommon.h
index e6fab69c..e3124e81 100644
--- a/arm9/lib/libnns/include/NNS_FND_heapcommon.h
+++ b/arm9/lib/libnns/include/NNS_FND_heapcommon.h
@@ -2,11 +2,26 @@
#define GUARD_NNS_FND_HEAPCOMMON_H
#include "NNS_FND_list.h"
+#include "MI_memory.h"
#define NNS_FND_HEAP_DEFAULT_ALIGNMENT 4
+#define NNS_FndGetFillValForHeap(type) (0)
+
typedef struct NNSiFndHeapHead NNSiFndHeapHead;
+typedef s32 NNSiIntPtr;
+typedef u32 NNSiUIntPtr;
+
+#define NNSi_FndGetBitValue(data, st, bits) (((data) >>(st)) & ((1 <<(bits)) -1))
+#define NNSi_FndSetBitValue(data, st, bits, val) do { \
+ u32 maskBits = (u32)((1 << (bits)) - 1); \
+ u32 newVal = (val) & maskBits; \
+ (void)(maskBits <<= st); \
+ (data) &= ~maskBits; \
+ (data) |= newVal << (st); \
+} while (FALSE);
+
struct NNSiFndHeapHead
{
u32 signature;
@@ -23,4 +38,74 @@ struct NNSiFndHeapHead
typedef NNSiFndHeapHead* NNSFndHeapHandle; // Type to represent heap handle
+static inline NNSiUIntPtr NNSiGetUIntPtr(const void* ptr)
+{
+ return (NNSiUIntPtr)ptr;
+}
+
+static inline u32 GetOffsetFromPtr(const void* start, const void* end)
+{
+ return NNSiGetUIntPtr(end) - NNSiGetUIntPtr(start);
+}
+
+static inline void* AddU32ToPtr(void* ptr, u32 val)
+{
+ return (void*)( NNSiGetUIntPtr(ptr) + val );
+}
+
+static inline const void* AddU32ToCPtr(const void* ptr, u32 val)
+{
+ return (const void*)( NNSiGetUIntPtr(ptr) + val );
+}
+
+static inline void* SubU32ToPtr(void* ptr, u32 val)
+{
+ return (void*)(NNSiGetUIntPtr(ptr) - val);
+}
+
+static inline const void* SubU32ToCPtr(const void* ptr, u32 val)
+{
+ return (const void*)(NNSiGetUIntPtr(ptr) - val);
+}
+
+static inline int ComparePtr(const void* a, const void* b)
+{
+ const u8* wa = a;
+ const u8* wb = b;
+
+ return wa - wb;
+}
+
+
+static inline u16 GetOptForHeap(const NNSiFndHeapHead* pHeapHd)
+{
+ return (u16)NNSi_FndGetBitValue(pHeapHd->attribute, 0, 8);
+}
+
+static inline void SetOptForHeap(
+ NNSiFndHeapHead* pHeapHd,
+ u16 optFlag
+ )
+{
+ NNSi_FndSetBitValue(pHeapHd->attribute, 0, 8, optFlag);
+}
+
+static inline void FillAllocMemory(NNSiFndHeapHead* pHeapHd, void* address, u32 size)
+{
+ if (GetOptForHeap(pHeapHd) & 1)
+ MI_CpuFill32(address, NNS_FndGetFillValForHeap(0), size);
+}
+
+void NNSi_FndInitHeapHead(NNSiFndHeapHead *pHead, u32 signature, void* heapStart, void* heapEnd, u16 optionFlag);
+
+void NNSi_FndFinalizeHeap(NNSiFndHeapHead *pHead);
+
+#define NNSi_FndRoundUp(value, alignment) (((value) + (alignment - 1)) & ~(alignment - 1))
+
+#define NNSi_FndRoundUpPtr(ptr, alignment) ((void*)NNSi_FndRoundUp(NNSiGetUIntPtr(ptr), alignment))
+
+#define NNSi_FndRoundDown(value, alignment) ((value) & ~(alignment - 1))
+
+#define NNSi_FndRoundDownPtr(ptr, alignment) ((void*)NNSi_FndRoundDown(NNSiGetUIntPtr(ptr), alignment))
+
#endif //GUARD_NNS_FND_HEAPCOMMON_H
diff --git a/arm9/lib/libnns/include/NNS_FND_list.h b/arm9/lib/libnns/include/NNS_FND_list.h
index 5fec2fdf..4bba7882 100644
--- a/arm9/lib/libnns/include/NNS_FND_list.h
+++ b/arm9/lib/libnns/include/NNS_FND_list.h
@@ -17,4 +17,19 @@ typedef struct
} NNSFndList;
+void NNS_FndInitList(
+ NNSFndList *pList,
+ s32 alignment
+);
+
+void NNS_FndAppendListObject(
+ NNSFndList *pList,
+ void* object
+);
+
+void NNS_FndRemoveListObject(
+ NNSFndList *pList,
+ void* object
+);
+
#endif //GUARD_NNS_FND_LIST_H
diff --git a/arm9/lib/libnns/src/NNS_FND_allocator.c b/arm9/lib/libnns/src/NNS_FND_allocator.c
new file mode 100644
index 00000000..c459c3d0
--- /dev/null
+++ b/arm9/lib/libnns/src/NNS_FND_allocator.c
@@ -0,0 +1,32 @@
+#include "nitro.h"
+#include "NNS_FND_allocator.h"
+#include "NNS_FND_expheap.h"
+
+ARM_FUNC void *AllocatorAllocForExpHeap(NNSFndAllocator * pAllocator, u32 size)
+{
+ return NNS_FndAllocFromExpHeapEx(pAllocator->pHeap, size, pAllocator->heapParam1);
+}
+
+ARM_FUNC void AllocatorFreeForExpHeap(NNSFndAllocator * pAllocator, void *memBlock)
+{
+ NNS_FndFreeToExpHeap(pAllocator->pHeap, memBlock);
+}
+
+ARM_FUNC void *NNS_FndAllocFromAllocator(NNSFndAllocator * pAllocator, u32 size)
+{
+ return pAllocator->pFunc->pfAlloc(pAllocator, size);
+}
+
+ARM_FUNC void NNS_FndFreeToAllocator(NNSFndAllocator * pAllocator, void *memBlock)
+{
+ pAllocator->pFunc->pfFree(pAllocator, memBlock);
+}
+
+ARM_FUNC void NNS_FndInitAllocatorForExpHeap(NNSFndAllocator * pAllocator, NNSFndHeapHandle pHeap, int alignment)
+{
+ static const NNSFndAllocatorFunc pFunc = {AllocatorAllocForExpHeap, AllocatorFreeForExpHeap};
+ pAllocator->pFunc = &pFunc;
+ pAllocator->pHeap = pHeap;
+ pAllocator->heapParam1 = alignment;
+ pAllocator->heapParam2 = 0;
+}
diff --git a/arm9/lib/libnns/src/NNS_FND_expheap.c b/arm9/lib/libnns/src/NNS_FND_expheap.c
new file mode 100644
index 00000000..62a4deb4
--- /dev/null
+++ b/arm9/lib/libnns/src/NNS_FND_expheap.c
@@ -0,0 +1,385 @@
+#include "global.h"
+#include "NNS_FND_expheap.h"
+
+typedef struct NNSiMemRegion {
+ void* start;
+ void* end;
+} NNSiMemRegion;
+
+static inline u16 GetAlignmentForMBlock(NNSiFndExpHeapMBlockHead* block)
+{
+ return NNSi_FndGetBitValue(block->attribute, 8, 7);
+}
+
+static inline void SetAllocDirForMBlock(NNSiFndExpHeapMBlockHead* pEHMBHead, u16 direction)
+{
+ NNSi_FndSetBitValue(pEHMBHead->attribute, 15, 1, direction);
+}
+
+static inline void SetAlignmentForMBlock(NNSiFndExpHeapMBlockHead* pEHMBHead, u16 alignment)
+{
+ NNSi_FndSetBitValue(pEHMBHead->attribute, 8, 7, alignment);
+}
+
+static inline void SetGroupIDForMBlock(NNSiFndExpHeapMBlockHead* pEHMBHead, u16 groupID)
+{
+ NNSi_FndSetBitValue(pEHMBHead->attribute, 0, 8, groupID);
+}
+
+static inline void* GetMemPtrForMBlock(NNSiFndExpHeapMBlockHead* block)
+{
+ return AddU32ToPtr(block, sizeof(NNSiFndExpHeapMBlockHead));
+}
+
+static inline void* GetMBlockHeadPtr(void* block)
+{
+ return SubU32ToPtr(block, sizeof(NNSiFndExpHeapMBlockHead));
+}
+
+static inline void* GetMBlockEndAddr(NNSiFndExpHeapMBlockHead* block)
+{
+ return AddU32ToPtr(GetMemPtrForMBlock(block), block->blockSize);
+}
+
+static inline u16 GetAllocMode(NNSiFndExpHeapHead* pExHeapHd)
+{
+ return NNSi_FndGetBitValue(pExHeapHd->feature, 0, 1);
+}
+
+static inline void SetAllocMode(NNSiFndExpHeapHead* pExHeapHd, u16 mode)
+{
+ NNSi_FndSetBitValue(pExHeapHd->feature, 0, 1, mode);
+}
+
+static inline NNSiFndExpHeapHead* GetExpHeapHeadPtrFromHeapHead(NNSiFndHeapHead* pHHead)
+{
+ return AddU32ToPtr(pHHead, sizeof(NNSiFndHeapHead));
+}
+
+static inline NNSiFndExpHeapHead* GetExpHeapHeadPtrFromHandle(NNSFndHeapHandle heap)
+{
+ return GetExpHeapHeadPtrFromHeapHead(heap);
+}
+
+static inline NNSiFndHeapHead* GetHeapHeadPtrFromExpHeapHead(NNSiFndExpHeapHead* pEHHead)
+{
+ return SubU32ToPtr(pEHHead, sizeof(NNSiFndHeapHead));
+}
+
+ARM_FUNC void GetRegionOfMBlock(NNSiMemRegion* region, NNSiFndExpHeapMBlockHead* block)
+{
+ region->start = SubU32ToPtr(block, GetAlignmentForMBlock(block));
+ region->end = GetMBlockEndAddr(block);
+}
+
+ARM_FUNC NNSiFndExpHeapMBlockHead* RemoveMBlock(NNSiFndExpMBlockList* list, NNSiFndExpHeapMBlockHead* block)
+{
+ NNSiFndExpHeapMBlockHead* const prev = block->pMBHeadPrev;
+ NNSiFndExpHeapMBlockHead* const next = block->pMBHeadNext;
+
+ if (prev != NULL)
+ {
+ prev->pMBHeadNext = next;
+ }
+ else
+ {
+ list->head = next;
+ }
+
+ if (next != NULL)
+ {
+ next->pMBHeadPrev = prev;
+ }
+ else
+ {
+ list->tail = prev;
+ }
+
+ return prev;
+}
+
+ARM_FUNC NNSiFndExpHeapMBlockHead* InsertMBlock(NNSiFndExpMBlockList* list, NNSiFndExpHeapMBlockHead* target, NNSiFndExpHeapMBlockHead* prev)
+{
+ NNSiFndExpHeapMBlockHead* next;
+ target->pMBHeadPrev = prev;
+ if (prev != NULL)
+ {
+ next = prev->pMBHeadNext;
+ prev->pMBHeadNext = target;
+ }
+ else
+ {
+ next = list->head;
+ list->head = target;
+ }
+ target->pMBHeadNext = next;
+ if (next != NULL)
+ {
+ next->pMBHeadPrev = target;
+ }
+ else
+ {
+ list->tail = target;
+ }
+
+ return target;
+}
+
+ARM_FUNC NNSiFndExpHeapMBlockHead* InitMBlock(const NNSiMemRegion* pRegion, u16 signature)
+{
+ NNSiFndExpHeapMBlockHead* block = pRegion->start;
+ block->signature = signature;
+ block->attribute = 0;
+ block->blockSize = GetOffsetFromPtr(GetMemPtrForMBlock(block), pRegion->end);
+ block->pMBHeadPrev = NULL;
+ block->pMBHeadNext = NULL;
+ return block;
+}
+
+static inline NNSiFndExpHeapMBlockHead* InitFreeMBlock(const NNSiMemRegion* region)
+{
+ return InitMBlock(region, 0x4652);
+}
+
+ARM_FUNC NNSiFndHeapHead* InitExpHeap(void* startAddress, void* endAddress, u16 optFlag)
+{
+ NNSiFndHeapHead* pHeapHd = (NNSiFndHeapHead*)startAddress;
+ NNSiFndExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead(pHeapHd);
+ NNSi_FndInitHeapHead(pHeapHd, 0x45585048, AddU32ToPtr(pExpHeapHd, sizeof(NNSiFndExpHeapHead)), endAddress, optFlag);
+ pExpHeapHd->groupID = 0;
+ pExpHeapHd->feature = 0;
+ SetAllocMode(pExpHeapHd, 0);
+
+ NNSiFndExpHeapMBlockHead* pMBHead;
+ NNSiMemRegion region;
+
+ region.start = pHeapHd->heapStart;
+ region.end = pHeapHd->heapEnd;
+ pMBHead = InitFreeMBlock(&region);
+
+ pExpHeapHd->mbFreeList.head = pMBHead;
+ pExpHeapHd->mbFreeList.tail = pMBHead;
+ pExpHeapHd->mbUsedList.head = NULL;
+ pExpHeapHd->mbUsedList.tail = NULL;
+
+ return pHeapHd;
+}
+
+static inline void AppendMBlock(NNSiFndExpMBlockList* list, NNSiFndExpHeapMBlockHead* block)
+{
+ (void) InsertMBlock(list, block, list->tail);
+}
+
+ARM_FUNC void* AllocUsedBlockFromFreeBlock(NNSiFndExpHeapHead* pEHHead, NNSiFndExpHeapMBlockHead* pMBHeadFree, void* mblock, u32 size, u16 direction)
+{
+ NNSiMemRegion freeRgnT;
+ NNSiMemRegion freeRgnB;
+ NNSiFndExpHeapMBlockHead* pMBHeadFreePrev;
+
+ GetRegionOfMBlock(&freeRgnT, pMBHeadFree);
+
+ freeRgnB.end = freeRgnT.end;
+ freeRgnB.start = AddU32ToPtr(mblock, size);
+ freeRgnT.end = SubU32ToPtr(mblock, sizeof(NNSiFndExpHeapMBlockHead));
+
+ pMBHeadFreePrev = RemoveMBlock(&pEHHead->mbFreeList, pMBHeadFree);
+
+ if (GetOffsetFromPtr(freeRgnT.start, freeRgnT.end) < sizeof(NNSiFndExpHeapMBlockHead))
+ {
+ freeRgnT.end = freeRgnT.start;
+ }
+ else
+ {
+ pMBHeadFreePrev = InsertMBlock(&pEHHead->mbFreeList, InitFreeMBlock(&freeRgnT), pMBHeadFreePrev);
+ }
+ if (GetOffsetFromPtr(freeRgnB.start, freeRgnB.end) < sizeof(NNSiFndExpHeapMBlockHead))
+ {
+ freeRgnB.start= freeRgnB.end;
+ }
+ else
+ {
+ (void)InsertMBlock(&pEHHead->mbFreeList, InitFreeMBlock(&freeRgnB), pMBHeadFreePrev);
+ }
+
+ FillAllocMemory(GetHeapHeadPtrFromExpHeapHead(pEHHead), freeRgnT.end, GetOffsetFromPtr(freeRgnT.end, freeRgnB.start));
+
+ NNSiFndExpHeapMBlockHead* pMBHeadNewUsed;
+ NNSiMemRegion region;
+
+ region.start = SubU32ToPtr(mblock, sizeof(NNSiFndExpHeapMBlockHead));
+ region.end = freeRgnB.start;
+
+ pMBHeadNewUsed = InitMBlock(&region, 0x5544);
+ SetAllocDirForMBlock(pMBHeadNewUsed, direction);
+ SetAlignmentForMBlock(pMBHeadNewUsed, (u16)GetOffsetFromPtr(freeRgnT.end, pMBHeadNewUsed));
+ SetGroupIDForMBlock(pMBHeadNewUsed, pEHHead->groupID);
+ AppendMBlock(&pEHHead->mbUsedList, pMBHeadNewUsed);
+
+ return mblock;
+}
+
+ARM_FUNC void* AllocFromHead(NNSiFndHeapHead* pHeapHd, u32 size, int alignment)
+{
+ NNSiFndExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead(pHeapHd);
+ const BOOL bAllocFirst = GetAllocMode(pExpHeapHd) == 0;
+ NNSiFndExpHeapMBlockHead* pMBlkHd = NULL;
+ NNSiFndExpHeapMBlockHead* pMBlkHdFound = NULL;
+ u32 foundSize = 0xFFFFFFFF;
+ void* foundMBlock = NULL;
+
+ for (pMBlkHd = pExpHeapHd->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext)
+ {
+ void *const mblock = GetMemPtrForMBlock(pMBlkHd);
+ void *const reqMBlock = NNSi_FndRoundUpPtr(mblock, alignment);
+ const u32 offset = GetOffsetFromPtr(mblock, reqMBlock);
+ if (pMBlkHd->blockSize >= size + offset && foundSize > pMBlkHd->blockSize)
+ {
+ pMBlkHdFound = pMBlkHd;
+ foundSize = pMBlkHd->blockSize;
+ foundMBlock = reqMBlock;
+ if (bAllocFirst || foundSize == size)
+ break;
+ }
+ }
+
+ if (!pMBlkHdFound)
+ return NULL;
+
+ return AllocUsedBlockFromFreeBlock(pExpHeapHd, pMBlkHdFound, foundMBlock, size, 0);
+}
+
+ARM_FUNC void* AllocFromTail(NNSiFndHeapHead* pHeapHd, u32 size, int alignment)
+{
+ NNSiFndExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead(pHeapHd);
+ const BOOL bAllocFirst = GetAllocMode(pExpHeapHd) == 0;
+ NNSiFndExpHeapMBlockHead* pMBlkHd = NULL;
+ NNSiFndExpHeapMBlockHead* pMBlkHdFound = NULL;
+ u32 foundSize = 0xFFFFFFFF;
+ void* foundMBlock = NULL;
+
+ for (pMBlkHd = pExpHeapHd->mbFreeList.tail; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadPrev)
+ {
+ void *const mblock = GetMemPtrForMBlock(pMBlkHd);
+ void *const mBlockEnd = AddU32ToPtr(mblock, pMBlkHd->blockSize);
+ void *const reqMBlock = NNSi_FndRoundDownPtr(SubU32ToPtr(mBlockEnd, size), alignment);
+ if (ComparePtr(reqMBlock, mblock) >= 0 && foundSize > pMBlkHd->blockSize)
+ {
+ pMBlkHdFound = pMBlkHd;
+ foundSize = pMBlkHd->blockSize;
+ foundMBlock = reqMBlock;
+ if (bAllocFirst || foundSize == size)
+ break;
+ }
+ }
+
+ if (!pMBlkHdFound)
+ return NULL;
+
+ return AllocUsedBlockFromFreeBlock(pExpHeapHd, pMBlkHdFound, foundMBlock, size, 1);
+}
+
+ARM_FUNC BOOL RecycleRegion(NNSiFndExpHeapHead* pEHHead, const NNSiMemRegion* pRegion)
+{
+ NNSiFndExpHeapMBlockHead* pBlkPtrFree = NULL;
+ NNSiMemRegion freeRgn = *pRegion;
+ NNSiFndExpHeapMBlockHead* pBlk;
+ for (pBlk = pEHHead->mbFreeList.head; pBlk; pBlk = pBlk->pMBHeadNext)
+ {
+ if (pBlk < (NNSiFndExpHeapMBlockHead*)pRegion->start)
+ {
+ pBlkPtrFree = pBlk;
+ continue;
+ }
+ if (pBlk == pRegion->end)
+ {
+ freeRgn.end = GetMBlockEndAddr(pBlk);
+ (void)RemoveMBlock(&pEHHead->mbFreeList, pBlk);
+ }
+ break;
+ }
+ if (pBlkPtrFree && GetMBlockEndAddr(pBlkPtrFree) == pRegion->start)
+ {
+ freeRgn.start = pBlkPtrFree;
+ pBlkPtrFree = RemoveMBlock(&pEHHead->mbFreeList, pBlkPtrFree);
+ }
+ if (GetOffsetFromPtr(freeRgn.start, freeRgn.end) < sizeof(NNSiFndExpHeapMBlockHead))
+ return FALSE;
+ InsertMBlock(&pEHHead->mbFreeList, InitFreeMBlock(&freeRgn), pBlkPtrFree);
+ return TRUE;
+}
+
+ARM_FUNC NNSFndHeapHandle NNS_FndCreateExpHeapEx(void *startAddress, u32 size, u16 optFlag)
+{
+ void* endAddress = NNSi_FndRoundDownPtr(AddU32ToPtr(startAddress, size), 4);
+ startAddress = NNSi_FndRoundUpPtr(startAddress, 4);
+ if (NNSiGetUIntPtr(startAddress) > NNSiGetUIntPtr(endAddress) || GetOffsetFromPtr(startAddress, endAddress) < sizeof(NNSiFndHeapHead) + sizeof(NNSiFndExpHeapHead) + sizeof(NNSiFndExpHeapMBlockHead) + 4)
+ return NULL;
+ return InitExpHeap(startAddress, endAddress, optFlag);
+}
+
+ARM_FUNC void NNS_FndDestroyExpHeap(NNSFndHeapHandle handle)
+{
+ NNSi_FndFinalizeHeap(handle);
+}
+
+ARM_FUNC void* NNS_FndAllocFromExpHeapEx(NNSFndHeapHandle handle, u32 size, int alignment)
+{
+ if (size == 0)
+ size = 1;
+ size = NNSi_FndRoundUp(size, 4);
+ if (alignment >= 0)
+ return AllocFromHead(handle, size, alignment);
+ else
+ return AllocFromTail(handle, size, -alignment);
+}
+
+/*
+ARM_FUNC u32 NNS_FndResizeForMBlockExpHeap(NNSFndHeapHandle heap, void *memBlock, u32 size)
+{
+ NNSiFndExpHeapHead* pEHHead;
+ NNSiFndExpHeapMBlockHead* pMBHead;
+ pEHHead = GetExpHeapHeadPtrFromHandle(heap);
+ pMBHead = GetMBlockHeadPtr(memBlock);
+ size = NNSi_FndRoundUp(size, 4);
+ if (size == pMBHead->blockSize)
+ return size;
+ if (size > pMBHead->blockSize)
+ {
+ void* crUsedEnd = GetMBlockEndAddr(pMBHead);
+ NNSiFndExpHeapMBlockHead* block;
+ for (block = pEHHead->mbFreeList.head; block; block = block->pMBHeadNext)
+ {
+ if (block == crUsedEnd)
+ break;
+ }
+ if (!block || size > pMBHead->blockSize + sizeof(NNSiFndExpHeapMBlockHead) + block->blockSize)
+ return 0;
+
+ NNSiMemRegion rgnNewFree;
+ void* oldFreeStart;
+ NNSiFndExpHeapMBlockHead* nextBlockPrev;
+
+ GetRegionOfMBlock(&rgnNewFree, block);
+ nextBlockPrev = RemoveMBlock(&pEHHead->mbFreeList, block);
+ oldFreeStart = rgnNewFree.start;
+ rgnNewFree.start = AddU32ToPtr(memBlock, size);
+ if (GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) < sizeof(NNSiFndExpHeapMBlockHead))
+ rgnNewFree.start = rgnNewFree.end;
+ pMBHead->blockSize = GetOffsetFromPtr(memBlock, rgnNewFree.start);
+ if (GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) >= sizeof(NNSiFndExpHeapMBlockHead))
+ (void)InsertMBlock(&pEHHead->mbFreeList, InitFreeMBlock(&rgnNewFree), nextBlockPrev);
+ FillAllocMemory(heap, oldFreeStart, GetOffsetFromPtr(oldFreeStart, rgnNewFree.start));
+ }
+ else
+ {
+ NNSiMemRegion rgnNewFree;
+ const u32 oldBlockSize = pMBHead->blockSize;
+ rgnNewFree.start = AddU32ToPtr(memBlock, size);
+ rgnNewFree.end = GetMBlockEndAddr(pMBHead);
+ pMBHead->blockSize = size;
+ if (!RecycleRegion(pEHHead, &rgnNewFree))
+ pMBHead->blockSize = oldBlockSize;
+ }
+ return pMBHead->blockSize;
+}
+*/
diff --git a/arm9/lib/libnns/src/NNS_FND_heapcommon.c b/arm9/lib/libnns/src/NNS_FND_heapcommon.c
new file mode 100644
index 00000000..73646030
--- /dev/null
+++ b/arm9/lib/libnns/src/NNS_FND_heapcommon.c
@@ -0,0 +1,55 @@
+#include "nitro.h"
+#include "NNS_FND_heapcommon.h"
+#include "NNS_FND_list.h"
+
+BOOL sRootListInitialized;
+NNSFndList sRootList;
+
+ARM_FUNC void *NNS_FndGetNextListObject(NNSFndList *, void *);
+
+ARM_FUNC static NNSiFndHeapHead* FindContainHeap(NNSFndList * pList, const void * memBlock)
+{
+ NNSiFndHeapHead * pHead = NULL;
+
+ while ((pHead = NNS_FndGetNextListObject(pList, pHead)) != NULL)
+ {
+ if (pHead->heapStart <= memBlock && memBlock < pHead->heapEnd)
+ {
+ NNSiFndHeapHead * ret = FindContainHeap(&pHead->childList, memBlock);
+ if (ret == NULL)
+ ret = pHead;
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+ARM_FUNC static NNSFndList* FindListContainHeap(const void * memBlock)
+{
+ NNSFndList* ret = &sRootList;
+ NNSiFndHeapHead* pHead = FindContainHeap(&sRootList, memBlock);
+ if (pHead != NULL)
+ ret = &pHead->childList;
+ return ret;
+}
+
+ARM_FUNC void NNSi_FndInitHeapHead(NNSiFndHeapHead *pHead, u32 signature, void* heapStart, void* heapEnd, u16 optionFlag)
+{
+ pHead->signature = signature;
+ pHead->heapStart = heapStart;
+ pHead->heapEnd = heapEnd;
+ pHead->attribute = 0;
+ SetOptForHeap(pHead, optionFlag);
+ NNS_FndInitList(&pHead->childList, 4);
+ if (!sRootListInitialized)
+ {
+ NNS_FndInitList(&sRootList, 4);
+ sRootListInitialized = TRUE;
+ }
+ NNS_FndAppendListObject(FindListContainHeap(pHead), pHead);
+}
+
+ARM_FUNC void NNSi_FndFinalizeHeap(NNSiFndHeapHead *pHead)
+{
+ NNS_FndRemoveListObject(FindListContainHeap(pHead), pHead);
+}
diff --git a/arm9/lib/libnns/src/NNS_FND_list.c b/arm9/lib/libnns/src/NNS_FND_list.c
new file mode 100644
index 00000000..fdab8188
--- /dev/null
+++ b/arm9/lib/libnns/src/NNS_FND_list.c
@@ -0,0 +1,128 @@
+#include "nitro.h"
+#include "NNS_FND_list.h"
+
+#define OBJ_TO_LINK(list, obj) ((NNSFndLink*)((void*)(obj) + (list)->offset))
+
+ARM_FUNC void NNS_FndInitList(NNSFndList* list, s32 alignment)
+{
+ list->headObject = NULL;
+ list->tailObject = NULL;
+ list->numObjects = 0;
+ list->offset = (u16)alignment;
+}
+
+ARM_FUNC static void SetFirstObject(NNSFndList* list, void* object)
+{
+ NNSFndLink* tail = OBJ_TO_LINK(list, object);
+ tail->nextObject = NULL;
+ tail->prevObject = NULL;
+ list->headObject = object;
+ list->tailObject = object;
+ list->numObjects++;
+}
+
+ARM_FUNC void NNS_FndAppendListObject(NNSFndList* list, void* object)
+{
+ if (list->headObject == NULL)
+ {
+ SetFirstObject(list, object);
+ }
+ else
+ {
+ NNSFndLink *tail = OBJ_TO_LINK(list, object);
+ tail->prevObject = list->tailObject;
+ tail->nextObject = NULL;
+ OBJ_TO_LINK(list, list->tailObject)->nextObject = object;
+ list->tailObject = object;
+ list->numObjects++;
+ }
+}
+
+ARM_FUNC void NNS_FndPrependListObject(NNSFndList* list, void* object)
+{
+ if (list->headObject == NULL)
+ {
+ SetFirstObject(list, object);
+ }
+ else
+ {
+ NNSFndLink *tail = OBJ_TO_LINK(list, object);
+ tail->prevObject = NULL;
+ tail->nextObject = list->headObject;
+ OBJ_TO_LINK(list, list->headObject)->prevObject = object;
+ list->headObject = object;
+ list->numObjects++;
+ }
+}
+
+ARM_FUNC void NNS_FndInsertListObject(NNSFndList* list, void* where, void* object)
+{
+ if (where == NULL)
+ {
+ NNS_FndAppendListObject(list, object);
+ }
+
+ else if (where == list->headObject)
+ {
+ NNS_FndPrependListObject(list, object);
+ }
+ else
+ {
+ NNSFndLink* tail = OBJ_TO_LINK(list, object);
+ void* prevObject = OBJ_TO_LINK(list, where)->prevObject;
+ NNSFndLink* head = OBJ_TO_LINK(list, prevObject);
+ tail->prevObject = prevObject;
+ tail->nextObject = where;
+ head->nextObject = object;
+ OBJ_TO_LINK(list, where)->prevObject = object;
+ list->numObjects++;
+ }
+}
+
+ARM_FUNC void NNS_FndRemoveListObject(NNSFndList* list, void* object)
+{
+ NNSFndLink* node = OBJ_TO_LINK(list, object);
+ if (node->prevObject == NULL)
+ {
+ list->headObject = node->nextObject;
+ }
+ else
+ {
+ OBJ_TO_LINK(list, node->prevObject)->nextObject = node->nextObject;
+ }
+ if (node->nextObject == NULL)
+ {
+ list->tailObject = node->prevObject;
+ }
+ else
+ {
+ OBJ_TO_LINK(list, node->nextObject)->prevObject = node->prevObject;
+ }
+ node->prevObject = NULL;
+ node->nextObject = NULL;
+ list->numObjects--;
+}
+
+ARM_FUNC void * NNS_FndGetNextListObject(NNSFndList* list, void* object)
+{
+ if (object == NULL)
+ {
+ return list->headObject;
+ }
+ else
+ {
+ return OBJ_TO_LINK(list, object)->nextObject;
+ }
+}
+
+ARM_FUNC void * NNS_FndGetPrevListObject(NNSFndList* list, void* object)
+{
+ if (object == NULL)
+ {
+ return list->tailObject;
+ }
+ else
+ {
+ return OBJ_TO_LINK(list, object)->prevObject;
+ }
+}