Annotation of qemu/roms/openbios/forth/bootstrap/memory.fs, revision 1.1.1.1

1.1       root        1: \ tag: forth memory allocation
                      2: \ 
                      3: \ Copyright (C) 2002-2003 Stefan Reinauer
                      4: \ 
                      5: \ See the file "COPYING" for further information about
                      6: \ the copyright and warranty status of this work.
                      7: \ 
                      8: 
                      9: \ 7.3.3.2 memory allocation
                     10: 
                     11: \ these need to be initialized by the forth kernel by now.
                     12: variable start-mem 0 start-mem !       \ start of memory
                     13: variable end-mem   0 end-mem   !       \ end of memory
                     14: variable free-list 0 free-list !       \ free list head
                     15: 
                     16: \ initialize necessary variables and write a valid 
                     17: \ free-list entry containing all of the memory.
                     18: \   start-mem: pointer to start of memory.
                     19: \   end-mem:   pointer to end of memory.
                     20: \   free-list: head of linked free list
                     21: 
                     22: : init-mem ( start-addr size )
                     23:   over dup
                     24:   start-mem !          \ write start-mem 
                     25:   free-list !          \ write first freelist entry
                     26:   2dup /n - swap !     \ write 'len'  entry
                     27:   over cell+ 0 swap !  \ write 'next' entry
                     28:   + end-mem  !         \ write end-mem 
                     29:   ;
                     30:  
                     31: \ --------------------------------------------------------------------
                     32: 
                     33: \ return pointer to smallest free block that contains 
                     34: \ at least nb bytes and the block previous the the 
                     35: \ actual block. On failure the pointer to the smallest
                     36: \ free block is 0.
                     37: 
                     38: : smallest-free-block ( nb -- prev ptr | 0 0 )
                     39:   0 free-list @
                     40:   fffffff 0 0 >r >r >r
                     41:   begin
                     42:     dup
                     43:   while
                     44:     ( nb prev pp R: best_nb best_pp )
                     45:     dup @ 3 pick r@ within if
                     46:       ( nb prev pp )
                     47:       r> r> r> 3drop            \ drop old smallest
                     48:       2dup >r >r dup @ >r       \ new smallest
                     49:     then
                     50:     nip dup                     \ prev = pp
                     51:     cell + @                    \ pp = pp->next
                     52:   repeat
                     53:   3drop r> drop r> r>
                     54: ;
                     55: 
                     56: 
                     57: \ --------------------------------------------------------------------
                     58: 
                     59: \ allocate size bytes of memory
                     60: \ return pointer to memory (or throws an exception on failure).
                     61: 
                     62: : alloc-mem ( size -- addr )
                     63: 
                     64:   \ make it legal (and fast) to allocate 0 bytes
                     65:   dup 0= if exit then
                     66: 
                     67:   aligned                      \ keep memory aligned.
                     68:   dup smallest-free-block      \ look up smallest free block.
                     69:   
                     70:   dup 0= if 
                     71:     \ 2drop
                     72:     -15 throw \ out of memory
                     73:   then
                     74:   
                     75:   ( al-size prev addr )
                     76:   
                     77:   \ If the smallest fitting block found is bigger than
                     78:   \ the size of the requested block plus 2*cellsize we
                     79:   \ can split the block in 2 parts. otherwise return a
                     80:   \ slightly bigger block than requested.
                     81: 
                     82:   dup @ ( d->len ) 3 pick cell+ cell+ > if
                     83:   
                     84:     \ splitting the block in 2 pieces.
                     85:     \ new block = old block + len field + size of requested mem
                     86:     dup 3 pick cell+ + (  al-size prev addr nd )
                     87: 
                     88:     \ new block len = old block len - req. mem size - 1 cell
                     89:     over @             ( al-size prev addr nd addr->len )
                     90:     4 pick             ( ... al-size )
                     91:     cell+ -            ( al-size prev addr nd nd nd->len )
                     92:     over !             ( al-size prev addr nd )
                     93: 
                     94:     over cell+ @       ( al-size prev addr nd addr->next )
                     95:                        \ write addr->next to nd->next
                     96:     over cell+ !       ( al-size prev addr nd )
                     97:     over 4 pick swap !
                     98:   else
                     99:     \ don't split the block, it's too small.
                    100:     dup cell+ @
                    101:   then
                    102: 
                    103:   ( al-size prev addr nd )
                    104: 
                    105:   \ If the free block we got is the first one rewrite free-list
                    106:   \ pointer instead of the previous entry's next field.
                    107:   rot dup 0= if drop free-list else cell+ then
                    108:   ( al-size addr nd prev->next|fl )
                    109:   !
                    110:   nip cell+    \ remove al-size and skip len field of returned pointer
                    111: 
                    112:   ;
                    113: 
                    114: 
                    115: \ --------------------------------------------------------------------
                    116:   
                    117: \ free block given by addr. The length of the
                    118: \ given block is stored at addr - cellsize.
                    119: \ 
                    120: \ merge with blocks to the left and right 
                    121: \ immediately, if they are free.
                    122: 
                    123: : free-mem ( addr len -- )
                    124: 
                    125:   \ we define that it is legal to free 0-byte areas
                    126:   0= if drop exit then
                    127:   ( addr )
                    128:        
                    129:   \ check if the address to free is somewhere within
                    130:   \ our available memory. This fails badly on discontigmem
                    131:   \ architectures. If we need more RAM than fits on one 
                    132:   \ contiguous memory area we are too bloated anyways. ;)
                    133:   
                    134:   dup start-mem @ end-mem @ within 0= if
                    135:  \   ." free-mem: no such memory: 0x" u. cr
                    136:     exit
                    137:   then
                    138: 
                    139:   /n -                         \ get real block address
                    140:   0 free-list @                        ( addr prev l )
                    141:   
                    142:   begin                                \ now scan the free list
                    143:     dup 0<> if                 \ only check len, if block ptr != 0
                    144:       dup dup @ cell+ + 3 pick < 
                    145:     else
                    146:       false
                    147:     then
                    148:   while 
                    149:     nip dup                    \ prev=l
                    150:     cell+ @                    \ l=l->next
                    151:   repeat
                    152: 
                    153:   ( addr prev l )
                    154: 
                    155:   dup 0<> if                           \ do we have free memory to merge with?
                    156:   
                    157:     dup dup @ cell+ + 3 pick  = if     \ hole hit. adding bytes.
                    158:       \ freeaddr = end of current block -> merge
                    159:       ( addr prev l )
                    160:       rot @ cell+              ( prev l f->len+cellsize )
                    161:       over @ +                 \ add l->len
                    162:       over !                   ( prev l )
                    163:       swap over cell+ @                \ f = l; l = l->next;
                    164: 
                    165:       \ The free list is sorted by addresses. When merging at the
                    166:       \ start of our block we might also want to merge at the end
                    167:       \ of it. Therefore we fall through to the next border check
                    168:       \ instead of returning.
                    169:       true                             \ fallthrough value
                    170:     else
                    171:       false                            \ no fallthrough
                    172:     then
                    173:     >r                                 \ store fallthrough on ret stack
                    174:     
                    175:     ( addr prev l )
                    176: 
                    177:     dup 3 pick dup @ cell+ + = if      \ hole hit. real merging.
                    178:       \ current block starts where block to free ends.
                    179:       \ end of free block addr = current block -> merge and exit
                    180:                                        ( addr prev l )
                    181:       2 pick dup @                     ( f f->len ) 
                    182:       2 pick @ cell+ +                 ( f newlen )
                    183:       swap !                           ( addr prev l )
                    184:       3dup drop
                    185:       0= if
                    186:        free-list
                    187:       else
                    188:        2 pick cell+ 
                    189:       then                             ( value prev->next|free-list )
                    190:       !                                        ( addr prev l )
                    191:       cell+ @ rot                      ( prev l->next addr )
                    192:       cell+ ! drop
                    193:       r> drop exit                     \ clean up return stack
                    194:     then
                    195: 
                    196:     r> if 3drop exit then              \ fallthrough? -> exit
                    197:   then
                    198:   
                    199:   \ loose block - hang it before current.
                    200: 
                    201:   ( addr prev l )
                    202: 
                    203:   \ hang block to free in front of the current entry.
                    204:   dup 3 pick cell+ !                   \ f->next = l;
                    205:   free-list @ = if                     \ is block to free new list head?
                    206:     over free-list !
                    207:   then
                    208:   
                    209:   ( addr prev )
                    210:   dup 0<> if                           \ if (prev) prev->next=f
                    211:     cell+ !
                    212:   else 
                    213:     2drop                              \ no fixup needed. clean up.
                    214:   then
                    215:     
                    216:   ;

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.