alloc.asm 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. ; vim: ts=4:et:sw=4:
  2. ; Copyleft (K) by Jose M. Rodriguez de la Rosa
  3. ; (a.k.a. Boriel)
  4. ; http://www.boriel.com
  5. ;
  6. ; This ASM library is licensed under the BSD license
  7. ; you can use it for any purpose (even for commercial
  8. ; closed source programs).
  9. ;
  10. ; Please read the BSD license on the internet
  11. ; ----- IMPLEMENTATION NOTES ------
  12. ; The heap is implemented as a linked list of free blocks.
  13. ; Each free block contains this info:
  14. ;
  15. ; +----------------+ <-- HEAP START
  16. ; | Size (2 bytes) |
  17. ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK
  18. ; +----------------+
  19. ; | Next (2 bytes) |---+
  20. ; +----------------+ <-+
  21. ; | Size (2 bytes) |
  22. ; +----------------+
  23. ; | Next (2 bytes) |---+
  24. ; +----------------+ |
  25. ; | <free bytes...>| | <-- If Size > 4, then this contains (size - 4) bytes
  26. ; | (0 if Size = 4)| |
  27. ; +----------------+ <-+
  28. ; | Size (2 bytes) |
  29. ; +----------------+
  30. ; | Next (2 bytes) |---+
  31. ; +----------------+ |
  32. ; | <free bytes...>| |
  33. ; | (0 if Size = 4)| |
  34. ; +----------------+ |
  35. ; <Allocated> | <-- This zone is in use (Already allocated)
  36. ; +----------------+ <-+
  37. ; | Size (2 bytes) |
  38. ; +----------------+
  39. ; | Next (2 bytes) |---+
  40. ; +----------------+ |
  41. ; | <free bytes...>| |
  42. ; | (0 if Size = 4)| |
  43. ; +----------------+ <-+
  44. ; | Next (2 bytes) |--> NULL => END OF LIST
  45. ; | 0 = NULL |
  46. ; +----------------+
  47. ; | <free bytes...>|
  48. ; | (0 if Size = 4)|
  49. ; +----------------+
  50. ;
  51. ; When a block is FREED, the previous and next pointers are examined to see
  52. ; if we can defragment the heap. If the block to be freed is just next to the
  53. ; previous, or to the next (or both) they will be converted into a single
  54. ; block (so defragmented).
  55. ; MEMORY MANAGER
  56. ; This library must be initialized calling __MEM_INIT with
  57. ; HL = BLOCK Start & DE = Length.
  58. ; An init directive is useful for initialization routines.
  59. ; They will be added automatically if needed.
  60. #include once <error.asm>
  61. #include once <heapinit.asm>
  62. ;
  63. ; ---------------------------------------------------------------------
  64. ; MEM_ALLOC
  65. ; Allocates a block of memory in the heap.
  66. ;
  67. ; Parameters
  68. ; BC = Length of requested memory block
  69. ;
  70. ; Returns:
  71. ; HL = Pointer to the allocated block in memory. Returns 0 (NULL)
  72. ; if the block could not be allocated (out of memory)
  73. ; ---------------------------------------------------------------------
  74. ;
  75. MEM_ALLOC:
  76. __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC)
  77. PROC
  78. LOCAL __MEM_LOOP
  79. LOCAL __MEM_DONE
  80. LOCAL __MEM_SUBTRACT
  81. LOCAL __MEM_START
  82. LOCAL TEMP, TEMP0
  83. TEMP EQU TEMP0 + 1
  84. ;- ld hl, 0
  85. ;- ld (TEMP), hl
  86. __MEM_START:
  87. ;- ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start
  88. inc z80_c ;- inc bc
  89. bne *+4
  90. inc z80_b
  91. inc z80_c ;- inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer
  92. bne *+4
  93. inc z80_b
  94. __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE
  95. lda z80_h ;- ld a,h ; HL = NULL (No memory available?)
  96. sta z80_a
  97. ora z80_l ;- or l
  98. #ifdef __MEMORY_CHECK__
  99. ;- ld a, ERROR_OutOfMemory
  100. jeq __ERROR ;- jp z, __ERROR
  101. #else
  102. bne *+3 ;- ret z ; NULL
  103. rts
  104. #endif
  105. ; HL = Pointer to Free block
  106. ldy #$00 ;- ld e,(hl)
  107. lda (z80_hl),y
  108. sta z80_e
  109. inc z80_l ;- inc hl
  110. bne *+4
  111. inc z80_h
  112. ldy #$00 ;- ld d,(hl)
  113. lda (z80_hl),y
  114. sta z80_d
  115. inc z80_l ;- inc hl ; DE = Block Length
  116. bne *+4
  117. inc z80_h
  118. lda z80_l ;- push hl ; HL = *pointer to -> next block
  119. pha
  120. lda z80_h
  121. pha
  122. lda z80_e ;- ex de,hl
  123. ldx z80_l
  124. stx z80_e
  125. sta z80_l
  126. lda z80_d
  127. ldx z80_h
  128. stx z80_d
  129. sta z80_h
  130. ora z80_a ;- or a ; CF = 0
  131. ;- sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length)
  132. jcs __MEM_DONE ;- jp nc, __MEM_DONE
  133. pla ;- pop hl
  134. sta z80_h
  135. pla
  136. sta z80_l
  137. lda z80_l ;- ld (TEMP), hl
  138. sta TEMP
  139. lda z80_h
  140. sta TEMP+1
  141. lda z80_e ;- ex de,hl
  142. ldx z80_l
  143. stx z80_e
  144. sta z80_l
  145. lda z80_d
  146. ldx z80_h
  147. stx z80_d
  148. sta z80_h
  149. ldy #$00 ;- ld e,(hl)
  150. lda (z80_hl),y
  151. sta z80_e
  152. inc z80_l ;- inc hl
  153. bne *+4
  154. inc z80_h
  155. ldy #$00 ;- ld d,(hl)
  156. lda (z80_hl),y
  157. sta z80_d
  158. lda z80_e ;- ex de,hl
  159. ldx z80_l
  160. stx z80_e
  161. sta z80_l
  162. lda z80_d
  163. ldx z80_h
  164. stx z80_d
  165. sta z80_h
  166. jmp __MEM_LOOP ;- jp __MEM_LOOP
  167. __MEM_DONE:
  168. ; A free block has been found.
  169. ; Check if at least 4 bytes remains free (HL >= 4)
  170. lda z80_l ;- push hl
  171. pha
  172. lda z80_h
  173. pha
  174. lda z80_c ;- exx ; exx to preserve bc
  175. ldx z80_cp
  176. stx z80_c
  177. sta z80_cp
  178. lda z80_b
  179. ldx z80_bp
  180. stx z80_b
  181. sta z80_bp
  182. lda z80_e
  183. ldx z80_ep
  184. stx z80_e
  185. sta z80_ep
  186. lda z80_d
  187. ldx z80_dp
  188. stx z80_d
  189. sta z80_dp
  190. lda z80_l
  191. ldx z80_lp
  192. stx z80_l
  193. sta z80_lp
  194. lda z80_h
  195. ldx z80_hp
  196. stx z80_h
  197. sta z80_hp
  198. pla ;- pop hl
  199. sta z80_h
  200. pla
  201. sta z80_l
  202. lda #<4 ;- ld bc,4
  203. sta z80_c
  204. lda #>4
  205. sta z80_b
  206. ora z80_a ;- or a
  207. ;- sbc hl,bc
  208. lda z80_c ;- exx
  209. ldx z80_cp
  210. stx z80_c
  211. sta z80_cp
  212. lda z80_b
  213. ldx z80_bp
  214. stx z80_b
  215. sta z80_bp
  216. lda z80_e
  217. ldx z80_ep
  218. stx z80_e
  219. sta z80_ep
  220. lda z80_d
  221. ldx z80_dp
  222. stx z80_d
  223. sta z80_dp
  224. lda z80_l
  225. ldx z80_lp
  226. stx z80_l
  227. sta z80_lp
  228. lda z80_h
  229. ldx z80_hp
  230. stx z80_h
  231. sta z80_hp
  232. jcs __MEM_SUBTRACT ;- jp nc, __MEM_SUBTRACT
  233. ; At this point...
  234. ; less than 4 bytes remains free. So we return this block entirely
  235. ; We must link the previous block with the next to this one
  236. ; (DE) => Pointer to next block
  237. ; (TEMP) => &(previous->next)
  238. ;
  239. pla ;- pop hl ; Discard current block pointer
  240. sta z80_h
  241. pla
  242. sta z80_l
  243. lda z80_e ;- push de
  244. pha
  245. lda z80_d
  246. pha
  247. lda z80_e ;- ex de,hl ; DE = Previous block pointer; (HL) = Next block pointer
  248. ldx z80_l
  249. stx z80_e
  250. sta z80_l
  251. lda z80_d
  252. ldx z80_h
  253. stx z80_d
  254. sta z80_h
  255. ldy #$00 ;- ld a,(hl)
  256. lda (z80_hl),y
  257. sta z80_a
  258. inc z80_l ;- inc hl
  259. bne *+4
  260. inc z80_h
  261. ldy #$00 ;- ld h,(hl)
  262. lda (z80_hl),y
  263. sta z80_h
  264. lda z80_a ;- ld l,a ; HL = (HL)
  265. sta z80_l
  266. lda z80_e ;- ex de,hl ; HL = Previous block pointer; DE = Next block pointer
  267. ldx z80_l
  268. stx z80_e
  269. sta z80_l
  270. lda z80_d
  271. ldx z80_h
  272. stx z80_d
  273. sta z80_h
  274. TEMP0:
  275. lda #<0 ;- ld hl,0 ; Pre-previous block pointer
  276. sta z80_l
  277. lda #>0
  278. sta z80_h
  279. lda z80_e ;- ld (hl),e
  280. ldy #$00
  281. sta (z80_hl),y
  282. inc z80_l ;- inc hl
  283. bne *+4
  284. inc z80_h
  285. lda z80_d ;- ld (hl), d ; LINKED
  286. ldy #$00
  287. sta (z80_hl),y
  288. pla ;- pop hl ; Returning block.
  289. sta z80_h
  290. pla
  291. sta z80_l
  292. rts ;- ret
  293. __MEM_SUBTRACT:
  294. ; At this point we have to store HL value (Length - BC) into (DE - 2)
  295. lda z80_e ;- ex de,hl
  296. ldx z80_l
  297. stx z80_e
  298. sta z80_l
  299. lda z80_d
  300. ldx z80_h
  301. stx z80_d
  302. sta z80_h
  303. ;- dec hl
  304. lda z80_d ;- ld (hl),d
  305. ldy #$00
  306. sta (z80_hl),y
  307. ;- dec hl
  308. lda z80_e ;- ld (hl),e ; Store new block length
  309. ldy #$00
  310. sta (z80_hl),y
  311. clc ;- add hl,de ; New length + DE => free-block start
  312. lda z80_l
  313. adc z80_e
  314. sta z80_l
  315. lda z80_h
  316. adc z80_d
  317. sta z80_h
  318. pla ;- pop de ; Remove previous HL off the stack
  319. sta z80_d
  320. pla
  321. sta z80_e
  322. lda z80_c ;- ld (hl),c ; Store length on its 1st word
  323. ldy #$00
  324. sta (z80_hl),y
  325. inc z80_l ;- inc hl
  326. bne *+4
  327. inc z80_h
  328. lda z80_b ;- ld (hl),b
  329. ldy #$00
  330. sta (z80_hl),y
  331. inc z80_l ;- inc hl ; Return hl
  332. bne *+4
  333. inc z80_h
  334. rts ;- ret
  335. ;- ENDP