Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / alloc
1 ;
2 ; alloc.s
3 ;
4 ; Redirectable memory allocation (MDW)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 ;----- External dependencies ------------------------------------------------
33
34 GET sapphire:msgs
35 GET sapphire:sapphire
36 GET sapphire:subAlloc
37
38 ;----- Main code ------------------------------------------------------------
39
40 AREA |Sapphire$$Code|,CODE,READONLY
41
42 ; --- alloc__halloc ---
43 ;
44 ; On entry: R0 == size of block to find
45 ;
46 ; On exit: CC and R0 == pointer to block, if possible
47 ; CS if not enough memory
48 ;
49 ; Use: Allocates memory from the OS_Heap area. This is mainly
50 ; useful for registering the OS_Heap heap as the current
51 ; allocator.
52
53 alloc__halloc ROUT
54
55 STMFD R13!,{R1-R3,R14} ;Save some registers away
56 MOV R3,R0 ;Move the size away
57 MOV R1,R12 ;Locate the heap address
58 MOV R0,#2 ;Allocate memory
59 SWI XOS_Heap ;Call the OS to allocate
60 BVS %99alloc__halloc ;If it failed, skip ahead
61 MOV R0,R2 ;Point at block it returned
62 LDMFD R13!,{R1-R3,R14} ;Find all the registers again
63 BICS PC,R14,#C_flag ;If successful, return CC
64
65 99alloc__halloc LDR R1,[R0,#0] ;Get the error number out
66 MOV R2,#&084 ;&184 is `Not enough memory'
67 ORR R2,R2,#&100 ;Complete the error number
68 CMP R1,R2 ;Is this right?
69 SWINE OS_GenerateError ;No -- something's screwed
70 LDMFD R13!,{R1-R3,R14} ;Find all the registers again
71 ORRS PC,R14,#C_flag ;No memory -- return CS
72
73 LTORG
74
75 ; --- alloc__hfree ---
76 ;
77 ; On entry: R0 == pointer to a block allocated by alloc_halloc
78 ;
79 ; On exit: --
80 ;
81 ; Use: Frees a block allocated by alloc_halloc, or indeed by
82 ; OS_Heap in the Sapphire fixed-size area. If anything goes
83 ; badly amiss, an error is generated.
84
85 alloc__hfree ROUT
86
87 STMFD R13!,{R0-R2,R14} ;Save some registers
88 MOV R2,R0 ;Move the pointer away
89 MOV R1,R12 ;Locate the heap address
90 MOV R0,#3 ;Free memory
91 SWI OS_Heap ;Free it, generating errors
92 LDMFD R13!,{R0-R2,PC}^ ;Return to caller
93
94 LTORG
95
96 ; --- alloc_register ---
97 ;
98 ; On entry: R0 == pointer to allocator function
99 ; R1 == pointer to free function
100 ; R2 == workspace pointer to pass to them in R12
101 ;
102 ; On exit: --
103 ;
104 ; Use: Registers two functions to be used as a heap manager by
105 ; alloc and free.
106 ;
107 ; The allocator is entered with R0 as the size of block
108 ; required, and should exit with CC and R0 == pointer to the
109 ; block allocated if successful, CS if there wasn't enough
110 ; memory and generate any other errors that occur. Registers
111 ; other than R0 must be preserved.
112 ;
113 ; The freer is entered with R0 == pointer to block to free.
114 ; It should exit with all registers preserved. If anything
115 ; goes wrong, it should generate an error.
116
117 EXPORT alloc_register
118 alloc_register ROUT
119
120 STMFD R13!,{R0-R5,R12,R14} ;Save some registers away
121 WSPACE alloc__wSpace ;Find my workspace
122
123 ; --- Search the list first ---
124
125 10 LDMIA R12,{R3-R5,R14} ;Load the values out
126 CMP R0,R4 ;Do they match up nicely?
127 CMPEQ R1,R5
128 CMPEQ R2,R14
129 LDMEQFD R13!,{R0-R5,R12,PC}^ ;Yes -- then return now
130 CMP R3,#0 ;End of the list?
131 MOVNE R12,R3 ;Yes -- get a copy the
132 BNE %10alloc_register ;And go back round again
133
134 20 MOV R4,R2 ;Keep the R12 value safe
135 MOV R3,R1 ;And the free routine ptr
136 MOV R2,R0 ;And the alloc routine ptr
137 MOV R1,#0
138
139 MOV R0,#alloc__nodeSize ;Find size of a node block
140 BL sub_alloc ;Try to allocate memory
141 SWIVS OS_GenerateError ;This is a major problem
142
143 STMIA R0,{R1-R4} ;Save values into block
144 STR R0,[R12,#0] ;And link this block in
145
146 LDMFD R13!,{R0-R5,R12,PC}^ ;Return to caller
147
148 ; --- alloc_useOSHeap ---
149 ;
150 ; On entry: R1 == pointer to OS_Heap-managed heap to use
151 ;
152 ; On exit: --
153 ;
154 ; Use: Registers an OS_Heap heap to use to allocate memory when
155 ; alloc is called.
156
157 EXPORT alloc_useOSHeap
158 alloc_useOSHeap ROUT
159
160 STMFD R13!,{R0-R2,R14} ;Save some registers
161 MOV R2,R1 ;Move into workspace pointer
162 ADR R0,alloc__halloc ;Point to OS_Heap allocator
163 ADR R1,alloc__hfree ;Point to OS_Heap freer
164 BL alloc_register ;Register them nicely
165 LDMFD R13!,{R0-R2,PC}^ ;Return to caller
166
167 ; --- alloc ---
168 ;
169 ; On entry: R0 == size of block to allocate from current heap
170 ;
171 ; On exit: R0 == pointer to block and CC if it all worked
172 ; CS if there wasn't enough memory (R0 corrupted)
173 ;
174 ; Use: Allocates R0 bytes from a heap manager. This routine will
175 ; attempt to allocate memory from the current heaps in order
176 ; of registration (i.e. the Sapphire OS_Heap first etc.) until
177 ; either one which can service the request is found, or all
178 ; the heaps have been tried.
179
180 EXPORT alloc
181 alloc ROUT
182
183 STMFD R13!,{R1-R5,R12,R14} ;Save some registers
184 WSPACE alloc__wSpace ;Find my workspace
185 ADD R5,R0,#4 ;Add in the overhead
186
187 ADR R1,alloc__list ;Find the list head item
188 10alloc CMP R1,#0 ;Have we reached the end?
189 BEQ %20alloc ;Yes -- couldn't do it then
190 LDMIA R1,{R2-R4,R12} ;Load values from block
191 MOV R0,R5 ;Get block size wanted
192 MOV R14,PC ;Set up return address
193 MOV PC,R3 ;Call the allocator
194 MOVCS R1,R2 ;If it failed, move on
195 BCS %10alloc ;And try the next heap
196
197 STR R1,[R0],#4 ;Save the node pointer
198 LDMFD R13!,{R1-R5,R12,R14} ;Return to caller with ptr
199 BICS PC,R14,#C_flag ;With C flag clear
200
201 20alloc LDMFD R13!,{R1-R5,R12,R14} ;Return to caller
202 ORRS PC,R14,#C_flag ;With no memory warning
203
204 LTORG
205
206 ; --- free ---
207 ;
208 ; On entry: R0 == pointer to block allocated by alloc
209 ;
210 ; On exit: --
211 ;
212 ; Use: Frees a block allocated by alloc, regardless of which heap
213 ; it came from.
214
215 EXPORT free
216 free ROUT
217
218 STMFD R13!,{R0,R1,R12,R14} ;Save some registers
219 LDR R1,[R0,#-4]! ;Load node pointer from block
220 ADD R1,R1,#alloc__free ;Find free and workspace ptr
221 LDMIA R1,{R1,R12} ;Load them out
222 MOV R14,PC ;Set up return address
223 MOV PC,R1 ;And call the routine
224 LDMFD R13!,{R0,R1,R12,PC}^ ;Return to caller done
225
226 LTORG
227
228 ; --- alloc_init ---
229 ;
230 ; On entry: --
231 ;
232 ; On exit: --
233 ;
234 ; Use: Initialises the alloc system, and sets it up to use the
235 ; kernel-provided OS_Heap area.
236
237 EXPORT alloc_init
238 alloc_init ROUT
239
240 STMFD R13!,{R0-R3,R12,R14} ;Save some registers
241 WSPACE alloc__wSpace ;Find the workspace
242 LDR R14,alloc__list ;Find the list head pointer
243 CMP R14,#0 ;Is it null?
244 LDMNEFD R13!,{R0-R3,R12,PC}^ ;Yes -- return then
245
246 ; --- Initialise allocator list ---
247 ;
248 ; This is essential -- both msgs and suballoc need to be
249 ; able to allocate memory immediately. We have to build the
250 ; whole link here, because we normally use suballoc to create
251 ; the link blocks!
252
253 MOV R0,#0 ;No next pointer yet
254 ADR R1,alloc__halloc ;Point to allocator
255 ADR R2,alloc__hfree ;And freer
256 LDR R3,sapph_heapBase ;Find the heap address
257 STMIA R12,{R0-R3} ;Save them all away
258
259 ; --- Set up other required things ---
260
261 BL sub_init ;Initialise suballocator
262 LDMFD R13!,{R0-R3,R12,PC}^ ;Return to caller
263
264 LTORG
265
266 alloc__wSpace DCD 0
267
268 ; --- alloc_error ---
269 ;
270 ; On entry: --
271 ;
272 ; On exit: V set and R0 == pointer to an error about not having enough
273 ; memory.
274 ;
275 ; Use: Returns an error suitable for displaying to a user if there
276 ; isn't enough memory left.
277
278 EXPORT alloc_error
279 alloc_error ROUT
280
281 STMFD R13!,{R1,R14} ;Save some registers
282 ADR R0,alloc__noMem ;Point to the error block
283 BL msgs_error ;Translate the error message
284 LDMFD R13!,{R1,R14} ;Unstack the registers
285 ORRS PC,R14,#V_flag ;Return with the error nicely
286
287 ; --- The message ---
288 ;
289 ; Note that we supply a default, since it may be msgs which
290 ; is saying that it's out of memory!
291
292 alloc__noMem DCD 1
293 DCB "allocNOMEM:Not enough memory",0
294
295 LTORG
296
297 ;----- Workspace ------------------------------------------------------------
298
299 ; --- Allocator list ---
300
301 ^ 0
302 alloc__next # 4 ;Address of next node
303 alloc__alloc # 4 ;The allocator for blocks
304 alloc__free # 4 ;The freer for blocks
305 alloc__R12 # 4 ;Workspace for allocator
306 alloc__nodeSize # 0 ;Size of this block
307
308 ; --- Workspace ---
309
310 ^ 0,R12
311 alloc__wStart # 0
312
313 alloc__list # alloc__nodeSize ;List of current allocators
314
315 alloc__wSize EQU {VAR}-alloc__wStart
316
317 AREA |Sapphire$$LibData|,CODE,READONLY
318
319 DCD alloc__wSize
320 DCD alloc__wSpace
321 DCD 0
322 DCD alloc_init
323
324 ;----- That's all, folks ----------------------------------------------------
325
326 END