chiark / gitweb /
Initial revision
[ssr] / StraySrc / Dynamite / dynamite / s / dynHeap
1 ;
2 ; dynHeap.s
3 ;
4 ; New heap management for Dynamite
5 ;
6 ; © 1994-1998 Straylight
7 ;
8 ;----- Licensing note -------------------------------------------------------
9 ;
10 ; This file is part of Straylight's Dynamite
11 ;
12 ; Dynamite is free software; you can redistribute it and/or modify
13 ; it under the terms of the GNU General Public License as published by
14 ; the Free Software Foundation; either version 2, or (at your option)
15 ; any later version.
16 ;
17 ; Dynamite is distributed in the hope that it will be useful,
18 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ; GNU General Public License for more details.
21 ;
22 ; You should have received a copy of the GNU General Public License
23 ; along with Dynamite.  If not, write to the Free Software Foundation,
24 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26
27 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31
32                 GET     libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36                 GET     libs:sh.fastMove
37
38                 GET     sh.dynArea
39                 GET     sh.dynTask
40                 GET     sh.wSpace
41
42                 GET     sh.messages
43
44 ;----- Macros ---------------------------------------------------------------
45
46                 MACRO
47 $label          DIR     $reg
48 $label          LDR     $reg,dyn_machine        ;Get the machine type
49                 CMP     $reg,#&A5               ;Is it a RISC PC?
50                 MEND
51
52 ;----- Main code ------------------------------------------------------------
53
54                 AREA    |Dynamite$$Code|,CODE,READONLY
55
56 ; --- dh_alloc ---
57 ;
58 ; On entry:     R0 == pointer to anchor
59 ;               R1 == size to allocate in bytes
60 ;               R2 == ID value to store
61 ;
62 ; On exit:      R0 and R1 preserved
63 ;               R2 == address of block allocated
64 ;
65 ; Use:          Allocates a block from the Dynamite heap.
66
67                 EXPORT  dh_alloc
68 dh_alloc        ROUT
69
70                 STMFD   R13!,{R0,R1,R3,R14}     ;Save some registers
71                 MOV     R3,R0                   ;Keep anchor pointer
72                 ADD     R0,R1,#blk__oHead+15    ;Put size in R0...
73                 BIC     R0,R0,#15               ;...after mangling suitably
74                 BL      dh__ensure              ;Ensure the memory's there
75                 BVS     %90dh_alloc             ;If not there, return error
76                 STR     R1,[R0,#blk__size]      ;Save the size in there
77                 STR     R3,[R0,#blk__anchor]    ;And the anchor address
78                 STR     R2,[R0,#blk__id]        ;Oh, and the ID value
79                 ADD     R2,R0,#blk__oHead       ;Return correct address
80                 STR     R2,[R3,#0]              ;And save address in anchor
81                 LDMFD   R13!,{R0,R1,R3,PC}^     ;And return to caller
82
83 90dh_alloc      ADD     R13,R13,#4              ;Don't restore R0 on exit
84                 LDMFD   R13!,{R1,R3,R14}        ;Unstack some registers
85                 ORRS    PC,R14,#V_flag          ;And return the error
86
87                 LTORG
88
89 ; --- dh_free ---
90 ;
91 ; On entry:     R0 == pointer to anchor of block to free
92 ;
93 ; On exit:      --
94 ;
95 ; Use:          Frees a Dynamite block.
96
97                 EXPORT  dh_free
98 dh_free         ROUT
99
100                 STMFD   R13!,{R1,R14}           ;Save some registers
101                 BL      dh__checkAnchor         ;Make sure the anchor's OK
102                 MOVVC   R14,#0                  ;If so, clear block's anchor
103                 STRVC   R14,[R1,#blk__anchor]   ;Zero the anchor (R14==0 !!)
104                 BLVC    dh__unCompact           ;Say the heap is uncompact
105                 LDMFD   R13!,{R1,PC}            ;Return to caller
106
107                 LTORG
108
109 ; --- dh_freeWithID ---
110 ;
111 ; On entry:     R0 == ID of all blocks to free
112 ;
113 ; On exit:      --
114 ;
115 ; Use:          Frees all allocated blocks with a given ID number.
116
117                 EXPORT  dh_freeWithID
118 dh_freeWithID   ROUT
119
120                 CMP     R0,#0                   ;Is he trying to free ID 0?
121                 ADREQL  R0,msg_errBadFreeAll    ;Yes -- that's an error
122                 ORREQS  PC,R14,#V_flag          ;So return it to him
123
124                 ; --- Do the freeing job ---
125                 ;
126                 ; We just tonk a 0 anchor over all blocks with a matching ID.
127
128                 STMFD   R13!,{R0-R4,R14}        ;Save some registers
129                 LDR     R2,dyn_heapSize         ;Load the current heap size
130                 DIR     R14                     ;Is it RISC PC?
131                 LDRGE   R1,dyn_areaBase         ;Yes -- load the area base
132                 RSBLT   R1,R2,#&01800000        ;No -- find the base anyway
133                 ADD     R2,R2,R1                ;Find the heap end address
134                 MOV     R3,#0                   ;Haven't freed anything yet
135
136 00dh_freeWithID CMP     R1,R2                   ;Have we reached the end?
137                 BGE     %10dh_freeWithID        ;Yes -- return then
138                 LDR     R14,[R1,#blk__id]       ;Get the block's ID
139                 SUBS    R14,R14,R0              ;Is it a match? (=> R14==0)
140                 STREQ   R14,[R1,#blk__anchor]   ;Yes -- blank out the anchor
141                 MOVEQ   R3,#1                   ;And remember we done this
142                 LDR     R14,[R1,#blk__size]     ;Load this block's size
143                 ADD     R14,R14,#blk__oHead+15  ;Add on the overhead size
144                 BIC     R14,R14,#15             ;And align to granularity
145                 ADD     R1,R1,R14               ;Move on to next block
146                 B       %00dh_freeWithID        ;And go round again
147
148                 ; --- We finished -- tidy up and return ---
149
150 10dh_freeWithID CMP     R3,#0                   ;Did we free anything?
151                 BLNE    dh__unCompact           ;Yes -- then heap isn't tidy
152                 LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
153
154                 LTORG
155
156 ; --- dh_blockInfo ---
157 ;
158 ; On entry:     R0 == address of block anchor
159 ;
160 ; On exit:      R0 preserved
161 ;               R1 == address of block
162 ;               R2 == size of block
163 ;               R3 == block ID
164 ;
165 ; Use:          Returns information about a Dynamite block
166
167                 EXPORT  dh_blockInfo
168 dh_blockInfo    ROUT
169
170                 STMFD   R13!,{R14}              ;Save the link register
171                 BL      dh__checkAnchor         ;Make sure anchor is kosher
172                 LDMVCIB R1,{R2,R3}              ;Yes -- load size and ID
173                 ADDVC   R1,R1,#blk__oHead       ;Point to the block
174                 LDMFD   R13!,{PC}               ;And return to caller
175
176                 LTORG
177
178 ; --- dh_changeID ---
179 ;
180 ; On entry:     R0 == address of anchor block, or 0 for all
181 ;               R1 == new ID
182 ;               R2 == old ID (if R0 == 0)
183 ;
184 ; On exit:      --
185 ;
186 ; Use:          This call is use to change the ID of either an individual
187 ;               block (R0 == address of anchor), or the ID of all the
188 ;               blocks with the ID passed in R2 (if R0 == 0).
189
190                 EXPORT  dh_changeID
191 dh_changeID     ROUT
192
193                 STMFD   R13!,{R0-R3,R14}        ;Stack some registers
194                 CMP     R0,#0                   ;Just one block to change?
195                 BEQ     %50dh_changeID          ;No -- jump ahead
196
197                 ; --- Change the ID of a specific block ---
198
199                 MOV     R2,R1                   ;Preserve the new ID
200                 BL      dh__checkAnchor         ;Check the anchor
201                 BVS     %99dh_changeID          ;It's garbish -- return error
202                 STR     R2,[R1,#blk__id]        ;Store the new id
203                 B       %98dh_changeID          ;And return to caller
204
205                 ; --- Change the ID of all blocks with ID R2 ---
206
207 50dh_changeID   LDR     R3,dyn_heapSize         ;Load the current heap size
208                 DIR     R14                     ;Is it RISC PC?
209                 LDRGE   R0,dyn_areaBase         ;Yes -- load the area base
210                 RSBLT   R0,R3,#&01800000        ;No -- find the base anyway
211                 ADD     R3,R3,R0                ;Find the heap end address
212
213 60dh_changeID   CMP     R0,R3                   ;Have we reached the end?
214                 BGE     %98dh_changeID          ;Yes -- return then
215                 LDR     R14,[R0,#blk__id]       ;Get the id of this block
216                 CMP     R14,R2                  ;Do we want to change it?
217                 STREQ   R1,[R0,#blk__id]        ;Yes -- make it so then
218                 LDR     R14,[R0,#blk__size]     ;Get the block size
219                 ADD     R14,R14,#blk__oHead+15  ;Add on the block size
220                 BIC     R14,R14,#15             ;And word align
221                 ADD     R0,R0,R14               ;Point to the next block
222                 B       %60dh_changeID          ;Keep on looking for blocks
223
224 98dh_changeID   LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
225
226 99dh_changeID   ADD     R13,R13,#4              ;Don't unstack R0
227                 LDMFD   R13!,{R1-R3,R14}        ;Get back registers
228                 ORRS    PC,R14,#V_flag          ;Return with error
229
230                 LTORG
231
232 ; --- dh__checkAnchor ---
233 ;
234 ; On entry:     R0 == address of anchor to check
235 ;
236 ; On exit:      R1 == address of block descriptor
237 ;
238 ; Use:          Ensures that a given anchor is valid.
239
240 dh__checkAnchor ROUT
241
242                 STMFD   R13!,{R14}              ;Save some registers
243                 LDR     R1,[R0,#0]              ;Load the block address
244                 SUB     R1,R1,#blk__oHead       ;Point to our information
245                 LDR     R14,[R1,#blk__anchor]   ;Load the block's anchor
246                 CMP     R0,R14                  ;Do they match up?
247                 ADRNEL  R0,msg_errBadAnchor     ;No -- point to error message
248                 LDMFD   R13!,{R14}              ;Restore registers
249                 BICEQS  PC,R14,#V_flag          ;Anchor OK -- clear V on exit
250                 ORRNES  PC,R14,#V_flag          ;Anchor duff -- return error
251
252                 LTORG
253
254 ; --- dh__ensure ---
255 ;
256 ; On entry:     R0 == number of bytes required (multiple of 16)
257 ;
258 ; On exit:      R0 == pointer to base of area allocated
259 ;
260 ; Use:          Ensures that there are R0 bytes available in the heap.  If
261 ;               there aren't R0 bytes available, it goes out of its way to
262 ;               ensure that there *are* by getting more.  If there still
263 ;               isn't enough, it compacts the heap and tries some more.
264
265 dh__ensure      ROUT
266
267                 STMFD   R13!,{R1-R5,R14}        ;Save some registers
268                 MOV     R1,R0                   ;Keep the size I want
269
270                 ; --- Try to find some space among the free blocks ---
271
272                 LDR     R3,dyn_heapSize         ;Load the current heap size
273                 DIR     R14                     ;Is it RISC PC?
274                 LDRGE   R2,dyn_areaBase         ;Yes -- load the area base
275                 RSBLT   R2,R3,#&01800000        ;No -- find the base anyway
276                 ADD     R3,R3,R2                ;Find the heap end address
277                 MOV     R5,#0                   ;No bytes found yet
278
279 00dh__ensure    CMP     R2,R3                   ;Is there more to go?
280                 BGE     %05dh__ensure           ;No -- then extend the heap
281
282                 LDR     R0,[R2,#blk__size]      ;Load this block's size
283                 ADD     R0,R0,#blk__oHead+15    ;Add on the overhead size
284                 BIC     R0,R0,#15               ;And align to granularity
285                 LDR     R14,[R2,#blk__anchor]   ;Is the block free?
286                 ADD     R2,R2,R0                ;Bump on block pointer
287                 CMP     R14,#0                  ;If so, anchor==0
288                 MOVNE   R5,#0                   ;If not, clear free size
289                 BNE     %00dh__ensure           ;And loop round again
290
291                 ; --- Found a free block ---
292
293                 CMP     R5,#0                   ;Is there a free block size?
294                 SUBEQ   R4,R2,R0                ;No -- this is the start then
295                 ADD     R5,R5,R0                ;Add on the size of this blk
296                 SUBS    R14,R5,R1               ;Is this big enough?
297                 BLT     %00dh__ensure           ;No -- keep on round
298
299                 ; --- Found a big enough space ---
300
301                 BEQ     %03dh__ensure           ;If no leftover, skip on
302                 ADD     R3,R4,R1                ;Point to bit left over
303                 MOV     R0,#0                   ;This block is free
304                 SUB     R2,R14,#blk__oHead      ;Subtract info overhead
305                 STMIA   R3,{R0,R2}              ;Save this in the block
306
307                 ; --- Return address of this memory ---
308
309 03dh__ensure    MOV     R0,R4                   ;Point to the free block
310                 LDMFD   R13!,{R1-R5,R14}        ;Unstack registers
311                 BICS    PC,R14,#V_flag          ;And clear error indicator
312
313                 ; --- Main size ensuring loop ---
314
315 05dh__ensure    LDR     R14,dyn_areaSize        ;Get the dynamic area size
316                 LDR     R2,dyn_heapSize         ;And the size we're using
317                 SUB     R3,R14,R2               ;How much do we have?
318                 SUBS    R3,R1,R3                ;And is it enough?
319                 BLE     %10dh__ensure           ;Yes -- skip onwards
320
321                 ; --- Try to get some more pages ---
322
323                 LDR     R14,dyn_pageSize        ;Load machine page size
324                 SUB     R14,R14,#1              ;Subtract one -- round up
325                 ADD     R3,R3,R14               ;Add it on for rounding
326                 LDR     R4,dyn_log2PageSize     ;Load the page size log
327                 MOV     R0,R3,LSR R4            ;How many do I need?
328                 BL      da_addPages             ;Get some more
329                 BVC     %10dh__ensure           ;It worked -- skip onwards
330
331                 ; --- Hmm... -- try compacting the heap ---
332
333                 BL      dh_compact              ;Try to compact the heap
334                 BCC     %05dh__ensure           ;If it did, try again
335
336                 ADRL    R0,msg_errNoMem         ;Point to the error
337                 LDMFD   R13!,{R1-R5,R14}        ;Restore the registers
338                 ORRS    PC,R14,#V_flag          ;And return to caller
339
340                 ; --- Extend the heap and return the base address ---
341
342 10dh__ensure    ADD     R14,R2,R1               ;Work out the new heap size
343                 STR     R14,dyn_heapSize        ;Save this away for later
344                 DIR     R0                      ;Get the heap's direcection
345                 LDRGE   R0,dyn_areaBase         ;Yes -- load the area base
346                 ADDGE   R0,R0,R2                ;And add the old heap size
347                 RSBLT   R0,R14,#&01800000       ;Otherwise find the heap base
348                 LDMFD   R13!,{R1-R5,R14}        ;Unstack registers
349                 BICS    PC,R14,#V_flag          ;And clear error indicator
350
351                 LTORG
352
353 ; --- dh_reduce ---
354 ;
355 ; On entry:     --
356 ;
357 ; On exit:      CS if there was nothing we could do
358 ;
359 ; Use:          Tries to shunt the free space in the heap off the end and
360 ;               back into the operating system's free pool.  It does it a
361 ;               little bit and then stops, rather like those workmen on the
362 ;               M40.
363
364                 EXPORT  dh_reduce
365 dh_reduce       ROUT
366
367                 STMFD   R13!,{R14}              ;Save some registers
368                 LDR     R14,dyn_hpFlags         ;Load the heap's flags
369                 TST     R14,#hpFlag_tidy        ;Is the heap tidy?
370                 LDREQ   R14,dyn_lockCount       ;No -- then load lock count
371                 CMPEQ   R14,#0                  ;Is the heap locked?
372                 BNE     %91dh_reduce            ;Yes -- then return CS now
373
374                 ; --- Do search for free blocks ---
375
376                 STMFD   R13!,{R0-R9}            ;Save some more registers
377                 LDR     R1,dyn_heapSize         ;Load the current heap size
378                 DIR     R14                     ;Is it RISC PC?
379                 LDRGE   R5,dyn_areaBase         ;Yes -- load the area base
380                 RSBLT   R5,R1,#&01800000        ;No -- find the base anyway
381                 ADD     R1,R1,R5                ;Find the heap end address
382                 MOV     R9,R5                   ;Remember heap base address
383
384                 ; --- Find a free block ---
385
386                 MOV     R7,#0                   ;No previous block
387 00dh_reduce     CMP     R5,R1                   ;Are we at the end yet?
388                 BGE     %04dh_reduce            ;Yes -- jump ahead a little
389
390                 LDR     R2,[R5,#blk__anchor]    ;Get the block's anchor addr
391                 CMP     R2,#0                   ;Is the block free?
392                 LDR     R2,[R5,#blk__size]      ;Get the block size
393                 ADD     R2,R2,#blk__oHead+15    ;Add on the overhead bytes
394                 BIC     R2,R2,#15               ;And word align the size
395                 MOVNE   R7,R5                   ;No -- remember where it is
396                 ADDNE   R5,R5,R2                ;...move on to next one
397                 BNE     %00dh_reduce            ;...go round for another one
398
399                 ; --- We've found a free block ---
400
401 01dh_reduce     ADD     R6,R5,R2                ;Point to the next block
402                 CMP     R6,R1                   ;Is that the end of the heap?
403                 MOVGE   R8,R7                   ;Yes -- set up prev pointer
404                 SUBGE   R2,R2,#blk__oHead       ;...take off overhead
405                 STRGE   R2,[R5,#blk__size]      ;...store overall block size
406                 BGE     %04dh_reduce            ;...and jump ahead a little
407
408                 ; --- Check for two free blocks together ---
409
410                 LDR     R0,[R6,#blk__anchor]    ;Does this have an anchor?
411                 CMP     R0,#0                   ;Check if it's free
412                 SUBNE   R2,R2,#blk__oHead       ;Not -- take off overhead
413                 STRNE   R2,[R5,#blk__size]      ;...store overall block size
414                 BNE     %02dh_reduce            ;...jump ahead a little
415
416                 ; --- Join two adjacent free blocks together ---
417
418                 LDR     R0,[R6,#blk__size]      ;Yes -- get its size
419                 ADD     R2,R0,R2                ;Concatenate the two blocks
420                 ADD     R2,R2,#blk__oHead+15    ;Add on the overhead bytes
421                 BIC     R2,R2,#15               ;And word align the size
422                 B       %01dh_reduce            ;And check again...
423
424                 ; --- We may be searching for the last block ---
425
426 02dh_reduce
427                 DIR     R14                     ;Get the heap direction
428                 MOVLT   R5,R6                   ;Down -- point to next block
429                 MOVLT   R8,R7                   ;...remember last block pos.
430                 BLT     %00dh_reduce            ;...and keep on searching
431
432                 ; --- There's a block to bring down ---
433
434                 LDR     R4,[R6,#blk__size]      ;Get size of block to move
435                 ADD     R4,R4,#blk__oHead+15    ;Add the flex overhead
436                 BIC     R4,R4,#15               ;And word align the size
437                 MOVS    R2,R4                   ;This is the size to move
438                 MOV     R0,R5                   ;Where to move it to
439                 MOV     R1,R6                   ;Where it is right now
440                 BLNE    dh__move                ;Copy it down PDQ
441                 ADD     R0,R5,R4                ;Point after block we moved
442                 MOV     R1,#0                   ;Block doesn't have an anchor
443                 STR     R1,[R0,#blk__anchor]    ;Store that away for later
444                 SUB     R1,R6,R5                ;Find the difference here
445                 SUB     R1,R1,#blk__oHead       ;Don't count this size here
446                 STR     R1,[R0,#blk__size]      ;Store the old size in free
447
448                 ; --- We need to fix up the block we moved ---
449
450                 LDR     R0,[R5,#blk__anchor]    ;Get the anchor pointer
451                 ADD     R1,R5,#blk__oHead       ;Point to the real data
452                 STR     R1,[R0]                 ;Store client's new anchor
453
454                 ; --- That's it -- return to caller ---
455
456                 B       %10dh_reduce    ;Return to caller
457
458                 ; --- We've reached the end of the heap ---
459                 ;
460                 ; Now things get a little more complicated:
461                 ;
462                 ; If the heap goes upwards, then there may be a free block
463                 ; on the end that we can free (R5 < R1), otherwise the heap
464                 ; is compacted.
465                 ;
466                 ; If the heap goes downwards, then R8 points to the block
467                 ; immediately before the last free one. If R8 is 0, then
468                 ; either the heap is compacted (the first block is not free)
469                 ; or there is only on free block, and it's at the lower
470                 ; end of the heap.
471
472 04dh_reduce
473                 DIR     R14                     ;Get the heap direction
474                 BGE     %05dh_reduce            ;Upwards --  jump ahead
475
476                 CMP     R8,#0                   ;Was there a previous block?
477                 BNE     %07dh_reduce            ;Yes -- compact heap then
478
479                 LDR     R14,[R9,#blk__anchor]   ;Get previous block anchor
480                 CMP     R14,#0                  ;Is the first block free?
481                 BNE     %90dh_reduce            ;No -- the heap is compacted
482
483                 LDR     R14,[R9,#blk__size]     ;Get the size of the free blk
484                 ADD     R14,R14,#blk__oHead+15  ;Add on the overhead
485                 BIC     R14,R14,#15             ;And correctly align
486                 ADD     R7,R9,R14               ;Point past the free block
487
488                 LDR     R0,dyn_areaSize         ;Get the area size
489                 RSB     R14,R0,#&01800000       ;Find the base address
490                 SUB     R5,R7,R14               ;Get size of unsused area
491                 SUB     R14,R0,R5               ;Get the area size left
492                 STR     R14,dyn_heapSize        ;Store it away nicely
493                 LDR     R14,dyn_log2PageSize    ;Get the log page size
494                 MOVS    R0,R5,LSR R14           ;How many pages can we free?
495                 BLNE    da_removePages          ;More than 0 -- free them
496                 B       %20dh_reduce            ;Return to caller
497
498                 ; --- Merge the last block with the free area ---
499
500 05dh_reduce     CMP     R5,R1                   ;Had we reached the end?
501                 BGE     %90dh_reduce            ;Yes -- heaps compact then
502
503                 SUB     R14,R5,R9               ;Get the used area size
504                 STR     R14,dyn_heapSize        ;And store it away
505                 LDR     R0,dyn_pageSize         ;Get the machine page size
506                 SUB     R0,R0,#1                ;Turn into a bitmask
507                 ADD     R5,R5,R0                ;Align this to page boundary
508                 BIC     R0,R5,R0                ;And finish off the align
509                 LDR     R1,dyn_areaSize         ;Get the dyn area size
510                 ADD     R1,R1,R9                ;Point to end of area
511                 SUBS    R0,R1,R0                ;Are these different?
512                 BEQ     %10dh_reduce            ;No -- return
513                 LDR     R14,dyn_log2PageSize    ;Get the log page size
514                 MOVS    R0,R0,LSR R14           ;How many pages can we free?
515                 BLNE    da_removePages          ;More than 0 -- free them
516                 B       %20dh_reduce            ;Return to caller
517
518                 ; --- Move a block in a downwards heap ---
519
520 07dh_reduce     LDR     R2,[R8,#blk__size]      ;Get size of block to move
521                 ADD     R2,R2,#blk__oHead+15    ;Add the flex overhead
522                 BIC     R2,R2,#15               ;And word align the size
523                 ADD     R0,R8,R2                ;Point to the free block
524                 LDR     R4,[R0,#blk__size]      ;Load out it's size
525                 ADD     R14,R4,#blk__oHead+15   ;Add the flex overhead
526                 BIC     R14,R14,#15             ;And word align the size
527                 ADD     R0,R0,R14               ;Point to the end of the blk
528                 SUB     R0,R0,R2                ;Copy the block to here
529                 MOV     R1,R8                   ;Where it is right now
530                 BLNE    dh__move                ;Copy it down PDQ
531                 MOV     R1,#0                   ;Block doesn't have an anchor
532                 STR     R1,[R8,#blk__anchor]    ;Store that away for later
533                 STR     R4,[R8,#blk__size]      ;Store the old size in free
534
535                 ; --- We need to fix up the block we moved ---
536
537                 LDR     R14,[R0,#blk__anchor]   ;Get the anchor pointer
538                 ADD     R0,R0,#blk__oHead       ;Point to the real data
539                 STR     R0,[R14]                ;Store client's new anchor
540
541                 ; --- That's it -- return ---
542
543 10dh_reduce     LDMFD   R13!,{R0-R9,R14}        ;Load back registers
544                 BICS    PC,R14,#C_flag          ;Return with C clear
545
546                 ; --- There wasn't anything to do -- we're compacted ---
547
548 20dh_reduce     LDR     R0,dyn_hpFlags          ;Load my flags
549                 ORR     R0,R0,#hpFlag_tidy      ;We're compacted
550                 STR     R0,dyn_hpFlags          ;Store back the flags
551                 LDMFD   R13!,{R0-R9,R14}        ;Load back registers
552                 BICS    PC,R14,#C_flag          ;Return with C clear
553
554                 ; --- Nothing could be done ---
555
556 90dh_reduce     LDMFD   R13!,{R0-R9}            ;Load back registers
557 91dh_reduce     LDMFD   R13!,{R14}              ;And the link too
558                 ORRS    PC,R14,#C_flag          ;Return with C set
559
560                 LTORG
561
562 ; --- dh_compact ---
563 ;
564 ; On entry:     --
565 ;
566 ; On exit:      --
567 ;
568 ; Use:          Does a full compaction of the heap.
569
570                 EXPORT  dh_compact
571 dh_compact      ROUT
572
573                 STMFD   R13!,{R14}              ;Stack the link register
574                 BL      dh_reduce               ;Try to reduce the heap
575                 LDMCSFD R13!,{PC}               ;If it couldn't, return CS
576 00dh_compact    BL      dh_reduce               ;Try to reduce the heap
577                 BCC     %00dh_compact           ;Did something -- try again
578                 LDMFD   R13!,{R14}              ;Return to caller...
579                 BICS    PC,R14,#C_flag          ;... saying we did something
580
581                 LTORG
582
583 ; --- dh__unCompact ---
584 ;
585 ; On entry:     --
586 ;
587 ; On exit:      --
588 ;
589 ; Use:          Marks the heap as being uncompact.
590
591 dh__unCompact   ROUT
592
593                 STMFD   R13!,{R14}              ;Stack the link register
594                 LDR     R14,dyn_hpFlags         ;Load the flags word
595                 TST     R14,#hpFlag_tidy        ;Is the tidy bit on?
596                 BICNE   R14,R14,#hpFlag_tidy    ;Clear the 'is tidy' bit
597                 STRNE   R14,dyn_hpFlags         ;Store back the flags
598                 BLNE    dt_message              ;Yes -- prod compactor
599                 LDMFD   R13!,{PC}^              ;Return to caller
600
601                 LTORG
602
603 ; --- dh_lock ---
604 ;
605 ; On entry:     --
606 ;
607 ; On exit:      R10 corrupted (SWIs don't care about this)
608 ;
609 ; Use:          Locks the heap, so that compaction entirely fails to happen.
610
611                 EXPORT  dh_lock
612 dh_lock         ROUT
613
614                 LDR     R10,dyn_lockCount       ;Load the old lock count
615                 ADD     R10,R10,#1              ;Bump the counter a little
616                 STR     R10,dyn_lockCount       ;Store the counter back
617                 MOVS    PC,R14                  ;And return to caller
618
619                 LTORG
620
621 ; --- dh_unlock ---
622 ;
623 ; On entry:     --
624 ;
625 ; On exit:      R10 corrupted (SWIs don't care about this)
626 ;
627 ; Use:          Unlocks the heap, so that compaction can happen again, maybe.
628
629                 EXPORT  dh_unlock
630 dh_unlock       ROUT
631
632                 LDR     R10,dyn_lockCount       ;Load the old lock count
633                 SUBS    R10,R10,#1              ;Knock the counter down
634                 STRGE   R10,dyn_lockCount       ;Store the counter back
635                 BEQ     dt_message              ;If now enabled, signal task
636                 MOVS    PC,R14                  ;And return to caller
637
638                 LTORG
639
640 ; --- dh_save ---
641 ;
642 ; On entry:     R0 == mask of registers to save
643 ;
644 ; On exit:      R10, R11 corrupted
645 ;
646 ; Use:          Saves a load of registers on the Dynamite relocation stack.
647 ;               The mask in R0 contains a bit set for each register to save:
648 ;               bit 3 set means save R3 etc.  Since this is a SWI, only
649 ;               R1-R9 can be saved on the stack.
650
651                 EXPORT  dh_save
652 dh_save         ROUT
653
654                 ; --- StrongARM friendly version 1st October 1996 [mdw] ---
655
656                 LDR     R10,dyn_stackPtr        ;Load the stack pointer
657
658                 TST     R0,#&03F
659                 BEQ     %f05
660                 MOVS    R11,R0,LSL #31
661                 STRCS   R1,[R10],#4
662                 TST     R0,#&3FC
663                 BEQ     %f00
664                 MOVS    R11,R0,LSL #29
665                 STRMI   R2,[R10],#4
666                 STRCS   R3,[R10],#4
667                 TST     R0,#&3F0
668                 BEQ     %f00
669                 MOVS    R11,R0,LSL #27
670                 STRMI   R4,[R10],#4
671                 STRCS   R5,[R10],#4
672                 TST     R0,#&3C0
673                 BEQ     %f00
674 05              MOVS    R11,R0,LSL #25
675                 STRMI   R6,[R10],#4
676                 STRCS   R7,[R10],#4
677                 MOVS    R11,R0,LSL #23
678                 STRMI   R8,[R10],#4
679                 STRCS   R9,[R10],#4
680 00
681                 STR     R10,dyn_stackPtr        ;Save stack pointer back
682                 MOVS    PC,R14                  ;And return to caller
683
684                 LTORG
685
686 ; --- dh_load ---
687 ;
688 ; On entry:     R0 == mask of registers to load
689 ;
690 ; On exit:      R10, R11 corrupted
691 ;
692 ; Use:          Loads a load of registers on the Dynamite relocation stack.
693 ;               The mask in R0 contains a bit set for each register to load:
694 ;               bit 3 set means load R3 etc.  Since this is a SWI, only
695 ;               R1-R9 can be read from the stack.
696
697                 EXPORT  dh_load
698 dh_load         ROUT
699
700                 ; --- StrongARM friendly version 1st October 1996 [mdw] ---
701
702                 LDR     R10,dyn_stackPtr        ;Load the stack pointer
703
704                 TST     R0,#&3F0
705                 BEQ     %f05
706                 MOVS    R11,R0,LSL #23
707                 LDRCS   R9,[R10,#-4]!
708                 LDRMI   R8,[R10,#-4]!
709                 TST     R0,#&0FF
710                 BEQ     %f00
711                 MOVS    R11,R0,LSL #25
712                 LDRCS   R7,[R10,#-4]!
713                 LDRMI   R6,[R10,#-4]!
714                 TST     R0,#&03F
715                 BEQ     %f00
716                 MOVS    R11,R0,LSL #27
717                 LDRCS   R5,[R10,#-4]!
718                 LDRMI   R4,[R10,#-4]!
719                 TST     R0,#&00F
720                 BEQ     %f00
721 05              MOVS    R11,R0,LSL #29
722                 LDRCS   R3,[R10,#-4]!
723                 LDRMI   R2,[R10,#-4]!
724                 MOVS    R11,R0,LSL #31
725                 LDRCS   R1,[R10,#4]!
726 00
727                 STR     R10,dyn_stackPtr        ;Save stack pointer back
728                 MOVS    PC,R14                  ;And return to caller
729
730                 LTORG
731
732 ; --- dh_extend ---
733 ;
734 ; On entry:     R0 == address of block anchor
735 ;               R1 == new size for block
736 ;
737 ; On exit:      R0 preserved
738 ;               R1 == address of block, may have moved
739 ;
740 ; Use:          Changes the size of a block.
741
742                 EXPORT  dh_extend
743 dh_extend       ROUT
744
745                 STMFD   R13!,{R2,R14}           ;Save some registers
746                 MOV     R2,R1                   ;Keep the size safe a while
747                 BL      dh__checkAnchor         ;Make sure anchor's kosher
748                 LDRVC   R1,[R1,#blk__size]      ;Load the size word nicely
749                 SUBVC   R2,R2,R1                ;Get the `by' value I need
750                 BLVC    dh_midExtend            ;Do the messing about
751                 LDMFD   R13!,{R2,PC}            ;Return to caller
752
753                 LTORG
754
755 ; --- dh_midExtend ---
756 ;
757 ; On entry:     R0 == address of block anchor
758 ;               R1 == byte offset from block start
759 ;               R2 == number of bytes to insert
760 ;
761 ; On exit:      R0 preserved
762 ;               R1 == address of block, may have moved
763 ;
764 ; Use:          Inserts or removes bytes at a given offset into a Dynamite
765 ;               heap block.
766
767                 EXPORT  dh_midExtend
768 dh_midExtend    ROUT
769
770                 STMFD   R13!,{R0,R2-R9,R14}     ;Save some registers
771                 MOV     R5,R0                   ;Keep the anchor address
772                 MOV     R6,R1                   ;And the byte offset
773                 MOV     R7,R2                   ;And the size to insert
774
775                 ; --- To start with, some sanity checks ---
776
777                 BL      dh__checkAnchor         ;Make sure anchor is OK
778                 BVS     %90dh_midExtend         ;If not, return error
779                 CMP     R7,#0                   ;Are we growing the block?
780                 ADDLT   R14,R6,R7               ;No -- get lowest byte access
781                 MOVGE   R14,R6                  ;Yes -- similarly
782                 CMP     R14,#0                  ;Is this off the end?
783                 ADRLTL  R0,msg_errBadMid        ;Yes -- point to error
784                 BLT     %90dh_midExtend         ;And return to caller
785                 LDR     R4,[R1,#blk__size]      ;Get the block's size
786                 CMP     R6,R4                   ;Are we going too far here?
787                 ADRGTL  R0,msg_errBadMid        ;Yes -- point to error
788                 BGT     %90dh_midExtend         ;And return to caller
789
790                 ; --- Now do the correct extend job ---
791
792                 CMP     R7,#0                   ;Are we growing the block?
793                 BEQ     %85dh_midExtend         ;Not changing -- return
794                 BLT     %50dh_midExtend         ;Shrinking -- skip to do that
795
796                 ; --- Make a block bigger ---
797                 ;
798                 ; We do this in 3 stages:
799                 ;
800                 ; * Get the amount of dead space at the end of the block, and
801                 ;   see if this is enough.
802                 ;
803                 ; * If not, gather together the free blocks immediately
804                 ;   following the block and add this to the dead space.
805                 ;
806                 ; * If we still don't have enough, we ensure a block of the
807                 ;   required size (plus block descriptor) and copy the data
808                 ;   into there.
809                 ;
810                 ; Registers will be used as follows:
811                 ;
812                 ; R5-R7 are original arguments
813                 ; R4 == current size of block
814                 ; R3 == size of area we have found
815                 ; R2 == base address of extension area
816                 ; R1 == base address of block
817
818                 ADD     R2,R1,R4                ;Find the end of the block
819                 ADD     R3,R4,#blk__oHead+15    ;Align block size to gran.
820                 BIC     R0,R3,#15               ;To get dead space too
821                 SUB     R3,R0,#blk__oHead       ;But don't have the overhead
822                 SUB     R3,R3,R4                ;Get size of the dead space
823                 CMP     R3,R7                   ;Is there enough for us?
824                 BGE     %30dh_midExtend         ;Yes -- use it then
825
826                 ; --- Now we must gather free blocks together nicely ---
827
828                 STMFD   R13!,{R8-R10}           ;Save some more registers
829                 ADD     R8,R1,R0                ;Find start of next block
830                 DIR     R14                     ;Which way is the heap going?
831                 LDRGE   R14,dyn_areaBase        ;Upwards -- get base address
832                 LDRGE   R10,dyn_heapSize        ;And the heap's size
833                 ADDGE   R10,R14,R10             ;To get the top of the heap
834                 MOVLT   R10,#&01800000          ;Downwards -- get heap top
835
836 05dh_midExtend  CMP     R8,R10                  ;Are we there yet?
837                 BGE     %10dh_midExtend         ;Yes -- stop there then
838                 LDR     R14,[R8,#blk__anchor]   ;Get the block's anchor
839                 CMP     R14,#0                  ;Is it a free block?
840                 BNE     %10dh_midExtend         ;No -- stop here then
841                 LDR     R9,[R8,#blk__size]      ;Get the block's size
842                 ADD     R9,R9,#blk__oHead+15    ;Add information overhead
843                 BIC     R9,R9,#15               ;And align size nicely
844                 ADD     R8,R8,R9                ;Move on to next block
845                 ADD     R3,R3,R9                ;And increase available space
846                 CMP     R3,R7                   ;Do we have enough yet?
847                 BLT     %05dh_midExtend         ;No -- go round again
848
849                 LDMFD   R13!,{R8-R10}           ;Restore the stack pointer
850                 B       %30dh_midExtend         ;And do the extend op
851
852                 ; --- Not enough space in free blocks ---
853                 ;
854                 ; We dh__ensure enough space in the heap, and copy the whole
855                 ; lot.
856
857 10dh_midExtend  LDMFD   R13!,{R8-R10}           ;Restore the stack pointer
858                 ADD     R0,R4,R7                ;Get the required size
859                 ADD     R0,R0,#blk__oHead+15    ;Add information overhead
860                 BIC     R0,R0,#15               ;And align size nicely
861                 BL      dh__ensure              ;Make the space available
862                 BVS     %90dh_midExtend         ;If it failed, return error
863                 LDR     R1,[R5,#0]              ;Reload anchor -- may move
864                 SUB     R1,R1,#blk__oHead       ;And find real block base
865                 ADD     R2,R4,#blk__oHead       ;Add on the info overhead
866                 BL      dh__move                ;Copy the data over
867                 ADD     R14,R0,#blk__oHead      ;Point to the usable area
868                 STR     R14,[R5,#0]             ;Save client's new anchor
869                 MOV     R14,#0                  ;Get a zero word
870                 STR     R14,[R1,#blk__anchor]   ;To mark old block as free
871                 BL      dh__unCompact           ;The heap is not compact now
872
873                 ; --- Set up registers for the resize op ---
874
875                 MOV     R1,R0                   ;Point at the new block base
876                 ADD     R2,R1,R4                ;Find area to extend from
877                 MOV     R3,R7                   ;And the size we have found
878
879                 ; --- Perform the block resize ---
880
881 30dh_midExtend  ADD     R14,R4,R7               ;Get the new block size
882                 STR     R14,[R1,#blk__size]     ;And save it away
883                 ADD     R3,R3,R4                ;Get the total area size
884                 ADD     R14,R14,#blk__oHead+15  ;Add overhead to new size
885                 BIC     R14,R14,#15             ;And align nicely
886
887                 ; --- Increase the heap size if we need to ---
888
889                 ADD     R0,R1,R14               ;Find the end of the area
890                 LDR     R9,dyn_heapSize         ;Load the current heap size
891                 DIR     R8                      ;Is it RISC PC?
892                 LDRGE   R8,dyn_areaBase         ;Yes -- load the area base
893                 RSBLT   R8,R9,#&01800000        ;No -- find the base anyway
894                 ADD     R9,R9,R8                ;Find the heap end address
895                 CMP     R0,R9                   ;Is end too high?
896                 SUBGT   R0,R0,R8                ;Yes -- get the heap size
897                 STRGT   R0,dyn_heapSize         ;...and store it back again
898
899                 ADD     R3,R3,#blk__oHead+15    ;Do the same for the whole...
900                 BIC     R3,R3,#15               ;... area size
901                 SUBS    R3,R3,R14               ;Get the space left at end
902                 BLE     %35dh_midExtend         ;Perfect fit -- skip on
903
904                 ; --- Insert a free block here ---
905
906                 ADD     R0,R1,R14               ;Find the end of the area
907                 MOV     R2,#0                   ;No anchor -- it's free
908                 SUB     R3,R3,#blk__oHead       ;Subtract overhead size
909                 STMIA   R0,{R2,R3}              ;Save in descriptor block
910
911                 ; --- Now split the block as required ---
912
913 35dh_midExtend  ADD     R1,R1,#blk__oHead       ;Point at usable part of blk
914                 ADD     R1,R1,R6                ;Find the split offset
915                 ADD     R0,R1,R7                ;Find where to move to
916                 SUBS    R2,R4,R6                ;How much we have to move
917                 BLNE    dh__move                ;Do the split op
918                 B       %85dh_midExtend         ;And return happily to caller
919
920                 ; --- We have to reduce a block ---
921
922 50dh_midExtend  ADD     R14,R4,R7               ;Get the new size
923                 STR     R14,[R1,#blk__size]     ;This is the new size
924                 ADD     R1,R1,#blk__oHead       ;Point at usable part of blk
925                 ADD     R1,R1,R6                ;Find the split offset
926                 ADD     R0,R1,R7                ;Find where to move to
927                 SUBS    R2,R4,R6                ;How much we have to move
928                 BLNE    dh__move                ;Do the split op
929
930                 ; --- Now update the size and insert free block ---
931
932                 ADD     R3,R4,R7                ;Find the new size
933                 ADD     R4,R4,#blk__oHead+15    ;Add overhead to new size
934                 BIC     R4,R4,#15               ;And align nicely
935                 ADD     R3,R3,#blk__oHead+15    ;Do the same for the whole...
936                 BIC     R3,R3,#15               ;... area size
937                 SUBS    R14,R4,R3               ;Get the space left at end
938                 BEQ     %85dh_midExtend         ;Perfect fit -- skip onwards
939
940                 ; --- Insert a free block here ---
941
942                 LDR     R1,[R5,#0]              ;Load the block address
943                 SUB     R1,R1,#blk__oHead       ;Point to the block descr.
944                 ADD     R0,R1,R3                ;Find the end of the area
945                 MOV     R2,#0                   ;No anchor -- it's free
946                 SUB     R3,R14,#blk__oHead      ;Subtract overhead size
947                 STMIA   R0,{R2,R3}              ;Save in descriptor block
948                 BL      dh__unCompact           ;The heap is not compact now
949
950                 ; --- Now everything is great ---
951
952 85dh_midExtend  LDR     R1,[R5,#0]              ;Load the block address
953                 LDMFD   R13!,{R0,R2-R9,R14}     ;Unstack registers
954                 BICS    PC,R14,#V_flag          ;And return to caller
955
956                 ; --- We failed miserably ---
957
958 90dh_midExtend  ADD     R13,R13,#4              ;Don't restore R0 on exit
959                 LDMFD   R13!,{R2-R9,R14}        ;Unstack registers
960                 ORRS    PC,R14,#V_flag          ;And return to caller
961
962                 LTORG
963
964 ; --- dh__move ---
965 ;
966 ; On entry:     R0 == destination of movement
967 ;               R1 == base of block to move
968 ;               R2 == size of block to move
969 ;
970 ; On exit:      --
971 ;
972 ; Use:          Shunts memory around in the heap, relocating everything that
973 ;               needs relocation.
974
975 dh__move        ROUT
976
977                 STMFD   R13!,{R3,R4,R14}        ;Save some registers
978                 BL      fastMove                ;Do the memory movement
979
980                 ; --- Now relocate entries on the stack ---
981
982 10dh__move      LDR     R4,dyn_stackPtr         ;Find the stack pointer now
983                 ADR     R3,dyn_stack            ;Point to the stack base
984 15dh__move      CMP     R3,R4                   ;Have we finished yet?
985                 BGE     %20dh__move             ;Yes -- return then
986                 LDR     R14,[R3],#4             ;Load next entry from stack
987                 SUB     R14,R14,R1              ;Subtract source address
988                 CMP     R14,R2                  ;Is it in the block?
989                 ADDLO   R14,R14,R0              ;Yes -- relocate
990                 STRLO   R14,[R3,#-4]            ;And store back in stack
991                 B       %15dh__move             ;And carry on relocating
992
993 20dh__move      LDMFD   R13!,{R3,R4,PC}^        ;Return to caller
994
995                 LTORG
996
997 ; --- dh_checkHeap ---
998 ;
999 ; On entry:     --
1000 ;
1001 ; On exit:      May return an error
1002 ;
1003 ; Use:          Checks the current internal format of the heap to make
1004 ;               sure that it hasn't been corrupted in any way.
1005 ;               If the integrity check fails then an error is returned.
1006
1007                 EXPORT  dh_checkHeap
1008 dh_checkHeap    ROUT
1009
1010                 STMFD   R13!,{R0-R7,R14}        ;Save some registers
1011
1012                 ; --- Start going throught the blocks ---
1013
1014                 LDR     R6,dyn_heapSize         ;Load the current heap size
1015                 DIR     R14                     ;Is it RISC PC?
1016                 LDRGE   R5,dyn_areaBase         ;Yes -- load the area base
1017                 RSBLT   R5,R6,#&01800000        ;No -- find the base anyway
1018                 ADD     R6,R6,R5                ;Find the heap end address
1019                 MOV     R9,R5                   ;Remember heap base address
1020
1021                 ; --- Find a block ---
1022
1023                 MOV     R7,R5                   ;Previous block
1024 00dh_checkHeap  CMP     R5,R6                   ;Are we at the end yet?
1025                 ADRGTL  R0,msg_errBadHeap2      ;Oops -- must have a bad len
1026                 BGT     %90dh_checkHeap         ;Gone past -- oops
1027                 BEQ     %50dh_checkHeap         ;Yes -- jump ahead a little
1028
1029                 MOV     R0,R5                   ;Get the base of area to chk
1030                 ADD     R1,R0,#blk__oHead       ;Get the overhead size
1031                 SWI     OS_ValidateAddress      ;Make sure this is kosher
1032                 ADRCSL  R0,msg_errBadHeap2      ;No -- must have a bad len
1033                 BCS     %90dh_checkHeap         ;If not, moan at client
1034                 LDR     R2,[R5,#blk__anchor]    ;Get the block's anchor addr
1035                 CMP     R2,#0                   ;Is the block free?
1036                 BEQ     %10dh_checkHeap         ;Yes -- jump ahead
1037
1038                 ; --- Make sure the anchor checks OK ---
1039
1040                 MOV     R7,R5                   ;This block could be wrong
1041                 MOV     R0,R2                   ;Get the base of area to chk
1042                 ADD     R1,R0,#4                ;Just check one word
1043                 SWI     OS_ValidateAddress      ;Make sure this is kosher
1044                 ADRCSL  R0,msg_errBadHeap3      ;Address must be dead then
1045                 BCS     %90dh_checkHeap         ;If not, moan at client
1046
1047                 LDR     R0,[R2,#0]              ;Load the anchors value
1048                 ADD     R14,R5,#blk__oHead      ;This is what R0 should be
1049                 CMP     R0,R14                  ;Do they match?
1050                 ADRNEL  R0,msg_errBadHeap1      ;No -- point to the error
1051                 BNE     %90dh_checkHeap         ;And return it joyfully
1052
1053                 ; --- Go round for more then ---
1054
1055 10dh_checkHeap  LDR     R3,[R5,#blk__size]      ;Get the block size
1056                 ADD     R3,R3,#blk__oHead+15    ;Add on the overhead bytes
1057                 BIC     R3,R3,#15               ;And word align the size
1058                 ADD     R5,R5,R3                ;Yes -- move on to next one
1059                 B       %00dh_checkHeap         ;...go round for another one
1060
1061 50dh_checkHeap  LDMFD   R13!,{R0-R7,R14}        ;Load registers back
1062                 BICS    PC,R14,#V_flag          ;Return without error
1063
1064 90dh_checkHeap  ADD     R13,R13,#4
1065                 STR     R7,[R0,#0]              ;Store as the error number!
1066                 LDMFD   R13!,{R1-R7,R14}        ;Load registers back
1067                 ORRS    PC,R14,#V_flag          ;Return with error
1068
1069                 LTORG
1070
1071 ; --- dh_changeAnchor ---
1072 ;
1073 ; On entry:     R0 == pointer to anchor for block
1074 ;               R1 == address of new anchor
1075 ;
1076 ; On exit:      --
1077 ;
1078 ; Use:          Adjusts a block's anchor, in case it moves.
1079
1080                 EXPORT  dh_changeAnchor
1081 dh_changeAnchor ROUT
1082
1083                 STMFD   R13!,{R2,R14}           ;Save a register
1084                 MOV     R2,R1                   ;Remember this value
1085                 BL      dh__checkAnchor         ;Make sure the anchor's OK
1086                 STRVC   R2,[R1,#blk__anchor]    ;Save the new anchor pointer
1087                 ADDVC   R14,R1,#blk__oHead      ;Skip onto the actual data
1088                 STRVC   R14,[R2,#0]             ;And set the new anchor up
1089                 LDMFD   R13!,{R2,PC}            ;Return to caller
1090
1091                 LTORG
1092
1093 ; --- dh_dump ---
1094 ;
1095 ; On entry:     --
1096 ;
1097 ; On exit:      --
1098 ;
1099 ; Use:          Outputs a textual description of the dynamite heap, giving
1100 ;               details of each block within it.
1101
1102 dh__preDump     LDR     R12,[R12]
1103
1104                 EXPORT  dh_dump
1105 dh_dump         ROUT
1106
1107                 STMFD   R13!,{R0-R4,R14}        ;Stack some registers
1108
1109                 LDR     R4,dyn_heapSize         ;Get the current heap size
1110                 DIR     R14                     ;Which direction does it go?
1111                 LDRGE   R2,dyn_areaBase         ;Up -- find the base then
1112                 RSBLT   R2,R4,#&1800000         ;Down -- start below the RMA
1113                 ADD     R3,R2,R4                ;Find the heap limit address
1114
1115                 ; --- Display information about the heap in general ---
1116
1117                 ADRL    R0,msg_dumpHpBase       ;Find the message
1118                 MOV     R1,R2                   ;Get the heap base address
1119                 BL      dh__writeHex            ;And display it
1120
1121                 MOV     R1,R4                   ;Get the heap size
1122                 ADRL    R0,msg_dumpHpSize       ;Find the message
1123                 BL      dh__writeHex            ;And display it
1124
1125                 LDR     R1,dyn_areaSize         ;Get the dynamic area size
1126                 ADRL    R0,msg_dumpHpArSz       ;Find the message
1127                 BL      dh__writeHex            ;And display it
1128
1129                 ; --- Now start on the loop ---
1130
1131 00              CMP     R2,R3                   ;Have we finished yet?
1132                 LDMCSFD R13!,{R0-R4,PC}^        ;Yes -- then return
1133
1134                 SWI     OS_NewLine              ;Start a new line here
1135
1136                 ADRL    R0,msg_dumpBlkAddr      ;Point to the message
1137                 ADD     R1,R2,#blk__oHead       ;Point to the current block
1138                 BL      dh__writeHex            ;Display it
1139
1140                 ADRL    R0,msg_dumpBlkSize      ;Point at the message
1141                 MOV     R0,R0                   ;No-op to prevent objasm bug!
1142                 LDR     R1,[R2,#blk__size]      ;Get the block's size
1143                 BL      dh__writeHex            ;Display it
1144
1145                 LDR     R1,[R2,#blk__id]        ;Load the magic ID
1146                 ADRL    R0,msg_dumpBlkId        ;Point at the message
1147                 BL      dh__writeHex            ;Display it nicely
1148
1149                 LDR     R1,[R2,#blk__anchor]    ;Find the anchor address
1150                 CMP     R1,#0                   ;Is the block free?
1151                 ADREQL  R0,msg_dumpBlkFree      ;Yes -- point to the message
1152                 SWIEQ   XOS_Write0              ;And display it on screen
1153                 ADRNEL  R0,msg_dumpBlkAnch      ;Otherwise show anchor addr
1154                 BLNE    dh__writeHex            ;And move on to next block
1155
1156                 LDR     R14,[R2,#blk__size]     ;Load the block size again
1157                 ADD     R14,R14,#blk__oHead+15  ;Add overhead and align
1158                 BIC     R14,R14,#15             ;To find the next block
1159                 ADD     R2,R2,R14               ;Move onto the next block
1160                 B       %b00                    ;And skip back into the loop
1161
1162 dh__writeHex    STMFD   R13!,{R2,R14}           ;Save some registers
1163                 SWI     XOS_Write0              ;Display the string
1164                 SUB     R13,R13,#12             ;Make a small buffer
1165                 MOV     R0,R1                   ;Get the number to display
1166                 MOV     R1,R13                  ;Point to the buffer
1167                 MOV     R2,#12                  ;The buffer size, sir
1168                 SWI     XOS_ConvertHex8         ;Convert it into ASCII
1169                 SWI     XOS_Write0              ;Display that too
1170                 SWI     XOS_NewLine             ;Move on to a new line
1171                 ADD     R13,R13,#12             ;Restore the stack pointer
1172                 LDMFD   R13!,{R2,PC}^           ;And return to caller
1173
1174                 LTORG
1175
1176 ;----- * Commands -----------------------------------------------------------
1177
1178                 AREA    |Dynamite$$Commands|,CODE,READONLY
1179
1180                 DCB     "Dynamite_HeapDump",0
1181                 DCD     dh__preDump
1182                 DCD     0
1183                 DCD     synt_heapDump
1184                 DCD     help_heapDump
1185
1186 ;----- Data structures ------------------------------------------------------
1187
1188 ; --- Block descriptors ---
1189
1190                 ^       0
1191 blk__anchor     #       4                       ;Address of block's anchor
1192 blk__size       #       4                       ;Block's size, as allocated
1193 blk__id         #       4                       ;Client's magic ID number
1194 blk__oHead      #       0                       ;Overhead on allocated blocks
1195
1196 ;----- That's all, folks ----------------------------------------------------
1197
1198                 END