Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

743 строки
14KB

  1. ; heap.s - deterministic generated-program free-list heap (E05-S01).
  2. ;
  3. ; The caller supplies the region; this module does not choose a generated-
  4. ; program heap address. All routines run in the generated program's current
  5. ; RAM bank. See src/common/heap.inc for the block layout and API.
  6. ;
  7. ; Allocation is first-fit in address order. A free block is split when the
  8. ; remainder is at least HEAP_MIN_BLOCK. Freeing inserts in address order and
  9. ; coalesces with the following free block(s) and then with the preceding one.
  10. ; Every boundary, size, magic, and double-free check is always on.
  11. .setcpu "6502"
  12. .include "../common/heap.inc"
  13. .export heap_init, heap_alloc, heap_free
  14. .export heap_base, heap_end, heap_free_head, heap_free_total, heap_error
  15. .segment "ZEROPAGE"
  16. heap_ptr: .res 2
  17. heap_ptr2: .res 2
  18. .segment "CODE"
  19. ; A/X = base (A must be 0), Y = pages (1..127). C=1 with HEAP_ERR_ARG on a
  20. ; malformed region. On success the heap is one free block.
  21. heap_init:
  22. sta heap_arg
  23. stx heap_arg+1
  24. sty heap_arg+2
  25. lda #HEAP_OK
  26. sta heap_error
  27. lda heap_arg+2
  28. beq @bad
  29. cmp #HEAP_MAX_PAGES+1
  30. bcs @bad
  31. lda heap_arg
  32. bne @bad
  33. lda heap_arg+1
  34. clc
  35. adc heap_arg+2
  36. bcs @bad
  37. cmp #$C1 ; heap must end at or below $C000
  38. bcs @bad
  39. sta heap_end+1
  40. lda #$00
  41. sta heap_end
  42. lda heap_arg+1
  43. sta heap_base+1
  44. lda #$00
  45. sta heap_base
  46. lda heap_base
  47. sta heap_free_head
  48. lda heap_base+1
  49. sta heap_free_head+1
  50. lda #$00
  51. sta heap_free_total
  52. lda heap_arg+2
  53. sta heap_free_total+1
  54. lda heap_base
  55. sta heap_ptr
  56. lda heap_base+1
  57. sta heap_ptr+1
  58. ldy #0
  59. lda #$00
  60. sta (heap_ptr),y ; size low
  61. iny
  62. lda heap_arg+2
  63. sta (heap_ptr),y ; size high = pages
  64. iny
  65. lda #$00
  66. sta (heap_ptr),y ; next low
  67. iny
  68. sta (heap_ptr),y ; next high
  69. clc
  70. rts
  71. @bad:
  72. lda #HEAP_ERR_ARG
  73. sta heap_error
  74. sec
  75. rts
  76. ; A/X = requested payload bytes. Returns A/X = payload, C=0; or A/X=0, C=1
  77. ; with heap_error. The payload is zeroed.
  78. heap_alloc:
  79. sta heap_req
  80. stx heap_req+1
  81. lda #HEAP_OK
  82. sta heap_error
  83. lda heap_req
  84. clc
  85. adc #HEAP_HEADER_SIZE
  86. sta heap_need
  87. lda heap_req+1
  88. adc #0
  89. sta heap_need+1
  90. bcc :+
  91. jmp @oom
  92. :
  93. lda heap_need
  94. and #1
  95. beq @rounded
  96. inc heap_need
  97. bne @rounded
  98. inc heap_need+1
  99. bne :+
  100. jmp @oom
  101. :
  102. @rounded:
  103. lda heap_need+1
  104. bpl :+
  105. jmp @oom
  106. :
  107. bne @min_ok
  108. lda heap_need
  109. cmp #HEAP_MIN_BLOCK
  110. bcs @min_ok
  111. lda #HEAP_MIN_BLOCK
  112. sta heap_need
  113. lda #0
  114. sta heap_need+1
  115. @min_ok:
  116. lda #0
  117. sta heap_prev
  118. sta heap_prev+1
  119. lda heap_free_head
  120. sta heap_cur
  121. lda heap_free_head+1
  122. sta heap_cur+1
  123. @walk:
  124. lda heap_cur
  125. ora heap_cur+1
  126. bne :+
  127. jmp @oom
  128. :
  129. lda heap_cur
  130. sta heap_ptr
  131. lda heap_cur+1
  132. sta heap_ptr+1
  133. ldy #0
  134. lda (heap_ptr),y
  135. sta heap_bsize
  136. iny
  137. lda (heap_ptr),y
  138. and #$7F
  139. sta heap_bsize+1
  140. lda heap_bsize+1
  141. cmp heap_need+1
  142. bcc @next
  143. bne @found
  144. lda heap_bsize
  145. cmp heap_need
  146. bcc @next
  147. @found:
  148. lda heap_bsize
  149. sec
  150. sbc heap_need
  151. sta heap_rem
  152. lda heap_bsize+1
  153. sbc heap_need+1
  154. sta heap_rem+1
  155. lda heap_rem+1
  156. beq :+
  157. jmp @split
  158. :
  159. lda heap_rem
  160. cmp #HEAP_MIN_BLOCK
  161. bcc :+
  162. jmp @split
  163. :
  164. jmp @use_whole
  165. @next:
  166. lda heap_cur
  167. sta heap_prev
  168. lda heap_cur+1
  169. sta heap_prev+1
  170. ldy #2
  171. lda (heap_ptr),y
  172. sta heap_cur
  173. iny
  174. lda (heap_ptr),y
  175. sta heap_cur+1
  176. jmp @walk
  177. @use_whole:
  178. lda heap_cur
  179. sta heap_block
  180. lda heap_cur+1
  181. sta heap_block+1
  182. lda heap_block
  183. sta heap_ptr
  184. lda heap_block+1
  185. sta heap_ptr+1
  186. ldy #2
  187. lda (heap_ptr),y
  188. sta heap_next
  189. iny
  190. lda (heap_ptr),y
  191. sta heap_next+1
  192. lda heap_prev
  193. ora heap_prev+1
  194. beq @uw_head
  195. lda heap_prev
  196. sta heap_ptr
  197. lda heap_prev+1
  198. sta heap_ptr+1
  199. ldy #2
  200. lda heap_next
  201. sta (heap_ptr),y
  202. iny
  203. lda heap_next+1
  204. sta (heap_ptr),y
  205. jmp @uw_removed
  206. @uw_head:
  207. lda heap_next
  208. sta heap_free_head
  209. lda heap_next+1
  210. sta heap_free_head+1
  211. @uw_removed:
  212. lda heap_free_total
  213. sec
  214. sbc heap_bsize
  215. sta heap_free_total
  216. lda heap_free_total+1
  217. sbc heap_bsize+1
  218. sta heap_free_total+1
  219. jsr @mark_used
  220. lda heap_bsize
  221. sec
  222. sbc #HEAP_HEADER_SIZE
  223. sta heap_zero_len
  224. lda heap_bsize+1
  225. sbc #0
  226. sta heap_zero_len+1
  227. jmp @zero_return
  228. @split:
  229. lda heap_cur
  230. sta heap_block
  231. lda heap_cur+1
  232. sta heap_block+1
  233. lda heap_block
  234. sta heap_ptr
  235. lda heap_block+1
  236. sta heap_ptr+1
  237. ldy #2
  238. lda (heap_ptr),y
  239. sta heap_next
  240. iny
  241. lda (heap_ptr),y
  242. sta heap_next+1
  243. lda heap_block
  244. clc
  245. adc heap_need
  246. sta heap_rem_block
  247. lda heap_block+1
  248. adc heap_need+1
  249. sta heap_rem_block+1
  250. lda heap_rem_block
  251. sta heap_ptr2
  252. lda heap_rem_block+1
  253. sta heap_ptr2+1
  254. ldy #0
  255. lda heap_rem
  256. sta (heap_ptr2),y
  257. iny
  258. lda heap_rem+1
  259. sta (heap_ptr2),y
  260. iny
  261. lda heap_next
  262. sta (heap_ptr2),y
  263. iny
  264. lda heap_next+1
  265. sta (heap_ptr2),y
  266. lda heap_prev
  267. ora heap_prev+1
  268. beq @sp_head
  269. lda heap_prev
  270. sta heap_ptr
  271. lda heap_prev+1
  272. sta heap_ptr+1
  273. ldy #2
  274. lda heap_rem_block
  275. sta (heap_ptr),y
  276. iny
  277. lda heap_rem_block+1
  278. sta (heap_ptr),y
  279. jmp @sp_linked
  280. @sp_head:
  281. lda heap_rem_block
  282. sta heap_free_head
  283. lda heap_rem_block+1
  284. sta heap_free_head+1
  285. @sp_linked:
  286. lda heap_need
  287. sta heap_bsize
  288. lda heap_need+1
  289. sta heap_bsize+1
  290. jsr @mark_used
  291. lda heap_free_total
  292. sec
  293. sbc heap_need
  294. sta heap_free_total
  295. lda heap_free_total+1
  296. sbc heap_need+1
  297. sta heap_free_total+1
  298. lda heap_need
  299. sec
  300. sbc #HEAP_HEADER_SIZE
  301. sta heap_zero_len
  302. lda heap_need+1
  303. sbc #0
  304. sta heap_zero_len+1
  305. jmp @zero_return
  306. @mark_used:
  307. lda heap_block
  308. sta heap_ptr
  309. lda heap_block+1
  310. sta heap_ptr+1
  311. ldy #0
  312. lda heap_bsize
  313. sta (heap_ptr),y
  314. iny
  315. lda heap_bsize+1
  316. ora #$80
  317. sta (heap_ptr),y
  318. iny
  319. lda #$5A
  320. sta (heap_ptr),y
  321. iny
  322. lda #$A5
  323. sta (heap_ptr),y
  324. rts
  325. @zero_return:
  326. lda heap_block
  327. clc
  328. adc #HEAP_HEADER_SIZE
  329. sta heap_ptr
  330. sta heap_ptr2
  331. lda heap_block+1
  332. adc #0
  333. sta heap_ptr+1
  334. sta heap_ptr2+1
  335. jsr heap_zero
  336. lda heap_ptr2
  337. ldx heap_ptr2+1
  338. clc
  339. rts
  340. @oom:
  341. lda #HEAP_ERR_OOM
  342. sta heap_error
  343. lda #0
  344. tax
  345. sec
  346. rts
  347. ; Zero heap_zero_len bytes at heap_ptr. A=0 and is preserved.
  348. heap_zero:
  349. ldx heap_zero_len+1
  350. beq @tail
  351. ldy #0
  352. lda #0
  353. @page:
  354. sta (heap_ptr),y
  355. iny
  356. bne @page
  357. inc heap_ptr+1
  358. dex
  359. bne @page
  360. @tail:
  361. ldy #0
  362. lda #0
  363. cpy heap_zero_len
  364. beq @done
  365. @byte:
  366. sta (heap_ptr),y
  367. iny
  368. cpy heap_zero_len
  369. bcc @byte
  370. @done:
  371. rts
  372. ; A/X = payload pointer. Null is a successful no-op. On success the block is
  373. ; free and coalesced; on failure C=1 and heap_error is set.
  374. heap_free:
  375. sta heap_arg
  376. stx heap_arg+1
  377. lda #HEAP_OK
  378. sta heap_error
  379. lda heap_arg
  380. ora heap_arg+1
  381. bne :+
  382. jmp @ok
  383. :
  384. lda heap_arg
  385. and #1
  386. beq :+
  387. jmp @corrupt
  388. :
  389. lda heap_arg
  390. sec
  391. sbc #HEAP_HEADER_SIZE
  392. sta heap_block
  393. lda heap_arg+1
  394. sbc #0
  395. sta heap_block+1
  396. bcs @header_ok
  397. jmp @corrupt
  398. @header_ok:
  399. lda heap_block+1
  400. cmp heap_base+1
  401. bcs :+
  402. jmp @corrupt
  403. :
  404. bne @above_base
  405. lda heap_block
  406. cmp heap_base
  407. bcs :+
  408. jmp @corrupt
  409. :
  410. @above_base:
  411. lda heap_block+1
  412. cmp heap_end+1
  413. bcc @in_range
  414. beq :+
  415. jmp @corrupt
  416. :
  417. lda heap_block
  418. cmp heap_end
  419. bcc :+
  420. jmp @corrupt
  421. :
  422. @in_range:
  423. lda heap_block
  424. sta heap_ptr
  425. lda heap_block+1
  426. sta heap_ptr+1
  427. ldy #0
  428. lda (heap_ptr),y
  429. sta heap_bsize
  430. iny
  431. lda (heap_ptr),y
  432. sta heap_bsize+1
  433. lda heap_bsize+1
  434. and #$80
  435. bne :+
  436. jmp @double
  437. :
  438. lda heap_bsize+1
  439. and #$7F
  440. sta heap_bsize+1
  441. lda heap_bsize+1
  442. bne @size_hi
  443. lda heap_bsize
  444. cmp #HEAP_MIN_BLOCK
  445. bcs :+
  446. jmp @corrupt
  447. :
  448. @size_hi:
  449. lda heap_bsize
  450. and #1
  451. beq :+
  452. jmp @corrupt
  453. :
  454. lda heap_block
  455. clc
  456. adc heap_bsize
  457. sta heap_tmp
  458. lda heap_block+1
  459. adc heap_bsize+1
  460. sta heap_tmp+1
  461. bcc :+
  462. jmp @corrupt
  463. :
  464. lda heap_tmp+1
  465. cmp heap_end+1
  466. bcc @size_ok
  467. beq :+
  468. jmp @corrupt
  469. :
  470. lda heap_tmp
  471. cmp heap_end
  472. beq :+
  473. jmp @corrupt
  474. :
  475. @size_ok:
  476. ldy #2
  477. lda (heap_ptr),y
  478. cmp #$5A
  479. beq :+
  480. jmp @corrupt
  481. :
  482. iny
  483. lda (heap_ptr),y
  484. cmp #$A5
  485. beq :+
  486. jmp @corrupt
  487. :
  488. ldy #0
  489. lda heap_bsize
  490. sta (heap_ptr),y
  491. iny
  492. lda heap_bsize+1
  493. sta (heap_ptr),y
  494. iny
  495. lda #0
  496. sta (heap_ptr),y
  497. iny
  498. sta (heap_ptr),y
  499. clc
  500. lda heap_free_total
  501. adc heap_bsize
  502. sta heap_free_total
  503. lda heap_free_total+1
  504. adc heap_bsize+1
  505. sta heap_free_total+1
  506. lda #0
  507. sta heap_prev
  508. sta heap_prev+1
  509. lda heap_free_head
  510. sta heap_cur
  511. lda heap_free_head+1
  512. sta heap_cur+1
  513. @find:
  514. lda heap_cur
  515. ora heap_cur+1
  516. beq @place
  517. lda heap_cur+1
  518. cmp heap_block+1
  519. bcc @advance
  520. bne @place
  521. lda heap_cur
  522. cmp heap_block
  523. bcc @advance
  524. bne :+
  525. jmp @double
  526. :
  527. jmp @place
  528. @advance:
  529. lda heap_cur
  530. sta heap_prev
  531. lda heap_cur+1
  532. sta heap_prev+1
  533. lda heap_cur
  534. sta heap_ptr
  535. lda heap_cur+1
  536. sta heap_ptr+1
  537. ldy #2
  538. lda (heap_ptr),y
  539. sta heap_cur
  540. iny
  541. lda (heap_ptr),y
  542. sta heap_cur+1
  543. jmp @find
  544. @place:
  545. lda heap_cur
  546. ora heap_cur+1
  547. beq @merged_next
  548. @merge_next:
  549. lda heap_block
  550. clc
  551. adc heap_bsize
  552. sta heap_tmp
  553. lda heap_block+1
  554. adc heap_bsize+1
  555. sta heap_tmp+1
  556. lda heap_tmp+1
  557. cmp heap_cur+1
  558. bne @merged_next
  559. lda heap_tmp
  560. cmp heap_cur
  561. bne @merged_next
  562. lda heap_cur
  563. sta heap_ptr
  564. lda heap_cur+1
  565. sta heap_ptr+1
  566. ldy #0
  567. lda (heap_ptr),y
  568. clc
  569. adc heap_bsize
  570. sta heap_bsize
  571. iny
  572. lda (heap_ptr),y
  573. adc heap_bsize+1
  574. sta heap_bsize+1
  575. ldy #2
  576. lda (heap_ptr),y
  577. sta heap_next
  578. iny
  579. lda (heap_ptr),y
  580. sta heap_next+1
  581. lda heap_next
  582. sta heap_cur
  583. lda heap_next+1
  584. sta heap_cur+1
  585. jmp @merge_next
  586. @merged_next:
  587. lda heap_block
  588. sta heap_ptr
  589. lda heap_block+1
  590. sta heap_ptr+1
  591. ldy #0
  592. lda heap_bsize
  593. sta (heap_ptr),y
  594. iny
  595. lda heap_bsize+1
  596. sta (heap_ptr),y
  597. iny
  598. lda heap_cur
  599. sta (heap_ptr),y
  600. iny
  601. lda heap_cur+1
  602. sta (heap_ptr),y
  603. lda heap_prev
  604. ora heap_prev+1
  605. beq @link_head
  606. lda heap_prev
  607. sta heap_ptr
  608. lda heap_prev+1
  609. sta heap_ptr+1
  610. ldy #0
  611. lda (heap_ptr),y
  612. sta heap_tmp
  613. iny
  614. lda (heap_ptr),y
  615. sta heap_tmp+1
  616. lda heap_prev
  617. clc
  618. adc heap_tmp
  619. sta heap_rem
  620. lda heap_prev+1
  621. adc heap_tmp+1
  622. sta heap_rem+1
  623. lda heap_rem+1
  624. cmp heap_block+1
  625. bne @link_prev_block
  626. lda heap_rem
  627. cmp heap_block
  628. bne @link_prev_block
  629. ldy #0
  630. lda heap_tmp
  631. clc
  632. adc heap_bsize
  633. sta (heap_ptr),y
  634. iny
  635. lda heap_tmp+1
  636. adc heap_bsize+1
  637. sta (heap_ptr),y
  638. iny
  639. lda heap_cur
  640. sta (heap_ptr),y
  641. iny
  642. lda heap_cur+1
  643. sta (heap_ptr),y
  644. jmp @ok
  645. @link_prev_block:
  646. ldy #2
  647. lda heap_block
  648. sta (heap_ptr),y
  649. iny
  650. lda heap_block+1
  651. sta (heap_ptr),y
  652. jmp @ok
  653. @link_head:
  654. lda heap_block
  655. sta heap_free_head
  656. lda heap_block+1
  657. sta heap_free_head+1
  658. jmp @ok
  659. @ok:
  660. lda #0
  661. tax
  662. clc
  663. rts
  664. @double:
  665. lda #HEAP_ERR_DOUBLE
  666. sta heap_error
  667. lda #0
  668. tax
  669. sec
  670. rts
  671. @corrupt:
  672. lda #HEAP_ERR_CORRUPT
  673. sta heap_error
  674. lda #0
  675. tax
  676. sec
  677. rts
  678. .segment "BSS"
  679. heap_base: .res 2
  680. heap_end: .res 2
  681. heap_free_head: .res 2
  682. heap_free_total: .res 2
  683. heap_error: .res 1
  684. heap_arg: .res 3
  685. heap_req: .res 2
  686. heap_need: .res 2
  687. heap_bsize: .res 2
  688. heap_rem: .res 2
  689. heap_rem_block: .res 2
  690. heap_cur: .res 2
  691. heap_prev: .res 2
  692. heap_next: .res 2
  693. heap_block: .res 2
  694. heap_tmp: .res 2
  695. heap_zero_len: .res 2

Powered by TurnKey Linux.