99;
1010; Please read the MIT license on the internet
1111
12- ; ----- IMPLEMENTATION NOTES ------
13- ; The heap is implemented as a linked list of free blocks.
14-
15- ; Each free block contains this info:
16- ;
17- ; +----------------+ <-- HEAP START
18- ; | Size (2 bytes) |
19- ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK
20- ; +----------------+
21- ; | Next (2 bytes) |---+
22- ; +----------------+ <-+
23- ; | Size (2 bytes) |
24- ; +----------------+
25- ; | Next (2 bytes) |---+
26- ; +----------------+ |
27- ; | <free bytes...>| | <-- If Size > 4, then this contains (size - 4) bytes
28- ; | (0 if Size = 4)| |
29- ; +----------------+ <-+
30- ; | Size (2 bytes) |
31- ; +----------------+
32- ; | Next (2 bytes) |---+
33- ; +----------------+ |
34- ; | <free bytes...>| |
35- ; | (0 if Size = 4)| |
36- ; +----------------+ |
37- ; <Allocated> | <-- This zone is in use (Already allocated)
38- ; +----------------+ <-+
39- ; | Size (2 bytes) |
40- ; +----------------+
41- ; | Next (2 bytes) |---+
42- ; +----------------+ |
43- ; | <free bytes...>| |
44- ; | (0 if Size = 4)| |
45- ; +----------------+ <-+
46- ; | Next (2 bytes) |--> NULL => END OF LIST
47- ; | 0 = NULL |
48- ; +----------------+
49- ; | <free bytes...>|
50- ; | (0 if Size = 4)|
51- ; +----------------+
52-
53-
54- ; When a block is FREED, the previous and next pointers are examined to see
55- ; if we can defragment the heap. If the block to be freed is just next to the
56- ; previous, or to the next (or both) they will be converted into a single
57- ; block (so defragmented).
58-
59-
60- ; MEMORY MANAGER
61- ;
62- ; This library must be initialized calling __MEM_INIT with
63- ; HL = BLOCK Start & DE = Length.
64-
65- ; An init directive is useful for initialization routines.
66- ; They will be added automatically if needed.
67-
68- #include once <error.asm>
69- #include once <mem/heapinit.asm>
70-
71-
72- ; ---------------------------------------------------------------------
73- ; MEM_ALLOC
74- ; Allocates a block of memory in the heap.
75- ;
76- ; Parameters
77- ; BC = Length of requested memory block
78- ;
79- ; Returns:
80- ; HL = Pointer to the allocated block in memory. Returns 0 (NULL)
81- ; if the block could not be allocated (out of memory)
82- ; ---------------------------------------------------------------------
83-
84- push namespace core
85-
86- MEM_ALLOC:
87- __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC)
88- PROC
89-
90- LOCAL __MEM_LOOP
91- LOCAL __MEM_DONE
92- LOCAL __MEM_SUBTRACT
93- LOCAL __MEM_START
94- LOCAL TEMP , TEMP0
95-
96- TEMP EQU TEMP0 + 1
97-
98- ld hl , 0
99- ld (TEMP) , hl
100-
101- __MEM_START:
102- ld hl , ZXBASIC_MEM_HEAP ; This label point to the heap start
103- inc bc
104- inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer
105-
106- __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE
107- ld a , h ; HL = NULL (No memory available?)
108- or l
109- #ifdef __MEMORY_CHECK__
110- ld a , ERROR_OutOfMemory
111- jp z , __ERROR
112- #else
113- ret z ; NULL
114- #endif
115- ; HL = Pointer to Free block
116- ld e , (hl)
117- inc hl
118- ld d , (hl)
119- inc hl ; DE = Block Length
120-
121- push hl ; HL = *pointer to -> next block
122- ex de , hl
123- or a ; CF = 0
124- sbc hl , bc ; FREE >= BC (Length) (HL = BlockLength - Length)
125- jp nc , __MEM_DONE
126- pop hl
127- ld (TEMP) , hl
128-
129- ex de , hl
130- ld e , (hl)
131- inc hl
132- ld d , (hl)
133- ex de , hl
134- jp __MEM_LOOP
135-
136- __MEM_DONE: ; A free block has been found.
137- ; Check if at least 4 bytes remains free (HL >= 4)
138- push hl
139- exx ; exx to preserve bc
140- pop hl
141- ld bc , 4
142- or a
143- sbc hl , bc
144- exx
145- jp nc , __MEM_SUBTRACT
146- ; At this point...
147- ; less than 4 bytes remains free. So we return this block entirely
148- ; We must link the previous block with the next to this one
149- ; (DE) => Pointer to next block
150- ; (TEMP) => &(previous->next)
151- pop hl ; Discard current block pointer
152- push de
153- ex de , hl ; DE = Previous block pointer; (HL) = Next block pointer
154- ld a , (hl)
155- inc hl
156- ld h , (hl)
157- ld l , a ; HL = (HL)
158- ex de , hl ; HL = Previous block pointer; DE = Next block pointer
159- TEMP0:
160- ld hl , 0 ; Pre-previous block pointer
161-
162- ld (hl) , e
163- inc hl
164- ld (hl) , d ; LINKED
165- pop hl ; Returning block.
166-
167- ret
168-
169- __MEM_SUBTRACT:
170- ; At this point we have to store HL value (Length - BC) into (DE - 2)
171- ex de , hl
172- dec hl
173- ld (hl) , d
174- dec hl
175- ld (hl) , e ; Store new block length
176-
177- add hl , de ; New length + DE => free-block start
178- pop de ; Remove previous HL off the stack
179-
180- ld (hl) , c ; Store length on its 1st word
181- inc hl
182- ld (hl) , b
183- inc hl ; Return hl
184- ret
185-
186- ENDP
187-
188- pop namespace
189-
12+ #include once [ arch:zx48k ] <mem/alloc.asm>
0 commit comments