Alchemy
Loading...
Searching...
No Matches

heap.c

Go to the documentation of this file.
1/// @file
2/// The heap: its two bump allocators and named slots.
3/// Part of runtime.c, the runtime object, compiled only through it.
4
6
7// The heap: two bump allocators, one in IWRAM up to Ram_IwramHeapEnd and one
8// in EWRAM up to its end (0x02040000), and 62 named slots for long-lived
9// blocks (enum HeapSlot). Nothing is freed one block at a time.
10
11/// Empties the heap: clears the 64 words of gWorkSlot (both pool pointers and
12/// every named slot) and sets the pools' next addresses to gIwramHeap and
13/// gEwramHeap. Called by System_Initialize, by Game_ResetForNewGame and by
14/// the debug modes that start over, so every earlier block is forgotten.
16 union HeapState *work = (union HeapState *)gWorkSlot;
17
18 Dma_Fill32(0, work, 0x100);
19 work->heap.nextIwram = gIwramHeap;
20 work->heap.nextEwram = gEwramHeap;
21}
22
23/// Returns the IWRAM bytes left to allocate, up to gCartridgeResetMarker
24/// (0x03007800), the same end the allocators test. Battle_RunEncounter calls
25/// it around each action and ignores the result.
27 union HeapState *work = (union HeapState *)gWorkSlot;
28
29 return (s32)(*(u8 (*)[]) & gCartridgeResetMarker) - (s32)work->heap.nextIwram;
30}
31
32/// Returns the EWRAM bytes left to allocate, up to the end of EWRAM.
33/// Battle_RunEncounter calls it around each action and ignores the result.
35 union HeapState *work = (union HeapState *)gWorkSlot;
36
37 return 0x02040000 - (s32)work->heap.nextEwram;
38}
39
40/// Returns heap slot `kind`'s block, first allocating `size` bytes for it
41/// (rounded up to words), from IWRAM when they fit and EWRAM otherwise. A new
42/// block advances that pool's next address and is stored in the slot, so
43/// later calls with the same `kind` return it until Runtime_ReleaseHeapBlock
44/// frees it. Returns NULL when neither pool has room. Called throughout the
45/// game for long-lived work blocks, and by WaitFrames for each frame's OAM
46/// list.
48 union HeapState *work;
49 s32 alignedSize;
50 u32 address;
51 u32 nextAddress;
52 u32 next;
53 u32 cachedAddress;
54
55 work = (union HeapState *)gWorkSlot;
56 cachedAddress = (u32)work->slots[kind];
57 if (cachedAddress == 0) {
58 cachedAddress = (u32)work->heap.nextIwram;
59 alignedSize = (((u32)size + 3) >> 2) * 4;
60 next = cachedAddress + alignedSize;
61 if (next >= (u32)Ram_IwramHeapEnd) {
62 address = (u32)work->heap.nextEwram;
63 nextAddress = address + alignedSize;
64 if (nextAddress >= 0x02040000U) {
65 return NULL;
66 }
67 work->heap.nextEwram = (void *)nextAddress;
68 work->slots[kind] = (void *)address;
69 return (void *)address;
70 }
71 work->heap.nextIwram = (void *)next;
72 work->slots[kind] = (void *)cachedAddress;
73 return (void *)cachedAddress;
74 }
75 return (void *)cachedAddress;
76}
77
78/// As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need
79/// room more than speed: the battle, shop and save work, among others.
80void *Runtime_AllocateBlock(s32 kind, s32 size) {
81 union HeapState *work;
82 u32 alignedSize;
83 u32 next;
84 u32 address;
85 u32 nextAddress;
86 u32 cachedAddress;
87
88 work = (union HeapState *)gWorkSlot;
89 cachedAddress = (u32)work->slots[kind];
90 if (cachedAddress == 0) {
91 address = (u32)work->heap.nextEwram;
92 alignedSize = (((u32)size + 3) >> 2) * 4;
93 next = address + alignedSize;
94 if (next >= 0x02040000U) {
95 address = (u32)work->heap.nextIwram;
96 nextAddress = address + alignedSize;
97 if (nextAddress >= (u32)Ram_IwramHeapEnd) {
98 return NULL;
99 }
100 work->heap.nextIwram = (void *)nextAddress;
101 work->slots[kind] = (void *)address;
102 return (void *)address;
103 }
104 work->heap.nextEwram = (void *)next;
105 work->slots[kind] = (void *)address;
106 return (void *)address;
107 }
108 return (void *)cachedAddress;
109}
110
111/// Allocates `size` bytes (rounded up to words) with no slot, from IWRAM when
112/// they fit and EWRAM otherwise, and advances that pool's next address.
113/// Returns NULL when neither has room. Called for short-lived buffers (decode
114/// buffers, RAM copies of code), which MemFree rewinds the pool over.
115void *MemAlloc(s32 size) {
116 union HeapState *work = (union HeapState *)gWorkSlot;
117 u32 nextAddress;
118 u32 next;
119 u32 allocationAddress;
120 u32 alignedWords = ((u32)size + 3) >> 2;
121
122 allocationAddress = (u32)work->heap.nextIwram;
123 size = alignedWords << 2;
124 next = allocationAddress + size;
125 if (next >= (u32)Ram_IwramHeapEnd) {
126 allocationAddress = (u32)work->heap.nextEwram;
127 nextAddress = allocationAddress + size;
128 if (nextAddress >= 0x02040000U) {
129 return NULL;
130 }
131 work->heap.nextEwram = (void *)nextAddress;
132 } else {
133 work->heap.nextIwram = (void *)next;
134 }
135 return (void *)allocationAddress;
136}
137
138/// As MemAlloc, but tries EWRAM first. Called mostly by the battle code and
139/// the credits for buffers too large to want IWRAM.
141 union HeapState *work = (union HeapState *)gWorkSlot;
142 u32 alternateNextAddress;
143 u32 primaryNextAddress;
144 u32 allocationAddress;
145 u32 alignedWords = ((u32)size + 3) >> 2;
146
147 allocationAddress = (u32)work->heap.nextEwram;
148 size = alignedWords << 2;
149 primaryNextAddress = allocationAddress + size;
150 if (primaryNextAddress >= 0x02040000U) {
151 allocationAddress = (u32)work->heap.nextIwram;
152 alternateNextAddress = allocationAddress + size;
153 if (alternateNextAddress >= (u32)Ram_IwramHeapEnd) {
154 return NULL;
155 }
156 work->heap.nextIwram = (void *)alternateNextAddress;
157 } else {
158 work->heap.nextEwram = (void *)primaryNextAddress;
159 }
160 return (void *)allocationAddress;
161}
162
163/// Reserved empty memory export; its historical purpose is not established.
#define Dma_Fill32(value, destination, size)
Fills size bytes at destination with the word value by DMA3.
Definition dma.h:30
u32 gCartridgeResetMarker
Written by the soft reset just before it restarts the cartridge, and cleared by System_Initialize; no...
s32 Runtime_GetRemainingIwram(void)
Returns the IWRAM bytes left to allocate, up to gCartridgeResetMarker (0x03007800),...
Definition heap.c:26
void Runtime_InitializeHeap(void)
Empties the heap: clears the 64 words of gWorkSlot (both pool pointers and every named slot) and sets...
Definition heap.c:15
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
void * MemAlloc(s32 size)
Allocates size bytes (rounded up to words) with no slot, from IWRAM when they fit and EWRAM otherwise...
Definition heap.c:115
s32 Runtime_GetRemainingEwram(void)
Returns the EWRAM bytes left to allocate, up to the end of EWRAM.
Definition heap.c:34
void * Runtime_AllocateBlock(s32 kind, s32 size)
As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need room more than speed: the b...
Definition heap.c:80
UNUSED void RuntimeMemory_ReservedNoOp(void)
Reserved empty memory export; its historical purpose is not established.
Definition heap.c:164
void * Runtime_AllocateHeapBlock(s32 kind, s32 size)
Returns heap slot kind's block, first allocating size bytes for it (rounded up to words),...
Definition heap.c:47
u8 gEwramHeap[]
u8 gIwramHeap[]
#define Ram_IwramHeapEnd
Definition ram_buffer.h:21
What every part of the runtime object shares: its includes and the library call two parts make.
#define NULL
Definition bilibin.h:6
void * gWorkSlot[]
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
The heap's 64 work slots, the first two holding the next free EWRAM and IWRAM addresses.
Definition heap_state.h:18
void * slots[64]
Each slot's block once allocated, else null; slots 0 and 1 are the pool pointers.
Definition heap_state.h:26
struct HeapState::@141110302170060006222316322227346102017231370075 heap