chiark / gitweb /
JPEG support and other fixes from Nick Clark
[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