Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 168 lines (137 sloc) 3.799 kb
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
;; Memory allocation.
;; by José Manuel Díez (jdiez)
;; licensed under MIT.
;;
;; http://u.jdiez.me/0x42c/kernel.html#x01e-kern-malloc
;; http://u.jdiez.me/0x42c/kernel.html#x022-kern-free
;; declares: malloc, free

:mem_start dat 0x6000 ; adjust these to your liking.
:mem_end dat 0x7fff

:alloc_init
    set a, [mem_start]
    set b, [mem_end]
    jsr set_initial_blocks
    set pc, pop

; void* malloc(int owner, int words)
:malloc
    set push, i
    set i, [mem_start]
    
    :malloc_loop
        ife [i], 0xffff
            set pc, malloc_found_free
        
        add i, 1
        add i, [i]
        add i, 2
        
        set pc, malloc_loop
    :malloc_found_free
        ife i, [mem_start] ; beginning
            set pc, malloc_allocate
        
        add i, 1
        
        ife [i], a
            set pc, malloc_prepare
        ifg [i], a
            set pc, malloc_check_overhead
            
        add i, 1
        add i, [i] ; size of block
        
        set pc, malloc_loop
        
    :malloc_check_overhead
        set push, b
        set b, [i]
        sub b, a
        ifg b, 3 ; plenty of space for overhead
            set pc, malloc_check_end
        
        sub i, 1
        set b, pop
        set [i], b ; it isn't worth dividing the space
        set push, i
        set pc, malloc_end
        
        :malloc_check_end
            set b, pop
            set pc, malloc_prepare
        
    :malloc_prepare
        sub i, 1
        set pc, malloc_allocate
        
    :malloc_allocate
        set push, i
        set push, i
        set [i], b
        add i, 1
        set [i], a
        add i, 1
        add i, a
        set b, pop
        set [i], b ; header pointer
        
        add i, 1
        set a, i
        set b, [mem_end]
        jsr set_initial_blocks
        set pc, malloc_end
           
    :malloc_end
        set a, pop
        add a, 2 ; real start of memory
        set i, pop
        set pc, pop

; void free(void* addr)
:free
    sub a, 2 ; user gives the first allocated word, header is two words back
    set [a], 0xffff ; free memory
    set push, a
    
    :free_check_forward
        add a, 1
        set b, [a]
        add a, b
        add a, 2 ; next header
        ife [a], 0xffff
            set pc, free_merge_forward
    
    :free_check_backwards
        set a, peek
        sub a, 1
        ifg a, [mem_start]
            set pc free_check_backwards_continue
            
        set pc, free_end
    
    :free_check_backwards_continue
        ife [a], 0x0 ; if previous footer is empty
            set pc, free_end
        
        set b, [a]
        set a, b
        ifn [a], 0xffff
            set pc, free_end
            
        set peek, a ; the previous push is unnecesary
        add a, 1
        set b, [a]
        add a, b
        add a, 2
                          
        set pc, free_merge_forward ; no need to check since we already know there's a blob of free memory there
        
    :free_merge_forward
        set [a], 0x0
        add a, 1
        set b, [a]
        set c, b ; previous block length
        set [a], 0x0
        add a, b
        ifn a, [mem_end]
            add a, 1 ; footer of this block
        set b, pop
        set push, b ; we'll need it at the end
        set [a], b
        set a, b
        add a, 1
        set b, [a]
        add b, c
        add b, 3 ; considering overhead
        set [a], b
        set pc, free_end
    
    :free_end
        set a, pop
        set pc, pop
        
; void set_initial_blocks(void memstart, void memend)
:set_initial_blocks
    set push, b
    set [a], 0xffff ; owner of free mem
    add a, 1
    sub b, a
    set [a], b ; space available
    set b, pop
    sub a, 1
    set [b], a
    
    set pc, pop

Something went wrong with that request. Please try again.