aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_asm/builtin_asm/std_bump_alloc.atk16
blob: 28eefbc1b031429297b823e7ee205301a985d9cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
; Heap bump allocator implementation
;
; Just below the MMIO segment, which starts at 0xE7F0, is the heap segment. The heap area
; grows down from 0xE7EF until it overlaps with the stack, which grows up from 0x8000.
;
; The stack pointer is stored in register SP, which is the general use register RH by spec.
;
; The interface consists of two functions, bump_alloc and bump_reset.
; The bump_alloc function allocates a block of memory from the heap,
;   returning the lowest address of the allocated block.
; The bump_reset function resets the heap to its initial state, freeing all allocated blocks.
;
; To initialize the bump allocator, call bump_reset.
;
; The bump allocator cannot free individual blocks, only reset the entire heap.
;
; The memory layout is as follows:
; 0xE7EF (heap_segment)       alloc_next value
; 0xE7EE downwards            allocated blocks
;
; The alloc_next value is a pointer to the next free word in the heap.
; It is stored in the first word of the heap.

@data bump_next_p heap_segment
@data bump_arena_start ${heap_segment - 1}

@data bump_reset_p bump_reset
@label bump_reset
  ; reset the heap to its initial state (zero allocated blocks)
  ; can be used to initialize the bump allocator
  ; parameters:         none
  ; return:             void
  stack_stash RA RB

  ldi bump_arena_start RA     ; RA := bump_arena_start pointer
  ldr RA RA                   ; RA := bump_arena_start

  ldi bump_next_p RB          ; RB := bump_next_p pointer
  ldr RB RB                   ; RB := bump_next_p

  str RA RB                   ; *bump_next_p = bump_arena_start

  stack_restore RA RB
  return

@data bump_alloc_p bump_alloc
@label bump_alloc
  ; allocate a block of memory from the heap, checking for overlap with the stack
  ; parameters:               RA = n of words to allocate
  ; return:                   RG = address of allocated block or 0 if allocation failed
  stack_stash RB RC

  ldi bump_next_p RB          ; RB := bump_next_p pointer
  ldr RB RB                   ; RB := bump_next_p
  ldr RB RG                   ; RG := *bump_next_p (address of next free word)

  sub RG RA RG                ; RG := RG - RA (new alloc_next value)

  ; check that the new alloc_next value does not overlap with the stack
  sub RG SP RC                ; RC := RG - SP
  bri sign bump_alloc_overlap ; if RC < 0, bump_alloc_overlap
                              ; otherwise allocation ok

@label bump_alloc_ok
  str RG RB                   ; *bump_next_p = RG

  inc RG                      ; RG := RG + 1 (lowest address of allocated block)

  jpi bump_alloc_return

@label bump_alloc_overlap
  ; allocation failed, return 0
  ldi 0 RG

@label bump_alloc_return
  stack_restore RB RC
  return