ReC98/libs/master.lib/memheap.asm

310 lines
7.8 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; master library
;
; Description:
; ヒープ型メモリマネージャ
;
; Functions:
; unsigned hmem_allocbyte( unsigned bytesize ) ;
; unsigned hmem_alloc( unsigned parasize ) ;
; void hmem_free( unsigned memseg ) ;
;
; Returns:
; unsigned hmem_alloc: (cy=0) 確保したセグメント
; 0(cy=1) 管理メモリ不足
;
; Notes:
; hmem_alloc 実行後は、mem_AllocID は 0になります。
; hmem_alloc(0)として呼び出すと、メモリ不足を返します。
;
; ヒープの構造
; 管理情報: 16bytes
; Using 2bytes 使用中なら1, 未使用なら 0
; NextSeg 2bytes 次のメモリブロックの先頭
; 末尾なら mem_OutSegと同じ値
; ID 2bytes 用途ID(確保時のmem_AllocIDの値を転写)
; 続くパラグラフがデータ部
;
; Assembly Language Note:
; AX以外の全てのレジスタを保存します。
;
; Running Target:
; MS-DOS
;
; Author:
; 恋塚昭彦
;
; Rebision History:
; 93/ 3/20 Initial
; 93/ 5/ 3 bugfix: hmem_allocbyte(2倍の確保がされていた(^^;)
; 93/11/ 7 [M0.21] a=hmem_alloc(x); b=hmem_alloc(y);
; hmem_free(a); hmem_free(b); としたときに
; mem_TopHeapが異常になるバグ修正(hmem_freeのbug)
; (末尾がholeでその直前で唯一のブロックを開放したとき)
; 93/11/ 7 [M0.21] hmem_freeが、holeが連接したときに接続する部分が
; おかしかった(;_;)
; 93/12/27 [M0.22] hmem_freeの連接接続が完全ではなかった
; 93/12/29 [M0.22] hmem_freeに渡される値の検査を少しいれた
; (最低値より小さいときと、using flagが1でないときは
; 何もせずreturnするようにした)
; 95/ 2/14 [M0.22k] mem_AllocID対応
; 95/ 3/19 [M0.22k] 確保サイズが(mem_OutSeg-mem_EndMark)以上なら
; 先に失敗を返すようにした。
; 95/ 3/21 [M0.22k] BUGFIX hmem_free() 先頭のブロックを開放したときに
; 直後がフリーブロックで、その次のフリーブロックが最終
; ブロックのときに、その最終フリーブロックを見失って
; mem_FirstHoleを0にしていた。
;  このため、次に末尾から2番目のブロックを開放しても
; 最初の空きを作ったと思って連接作業を行わず、
; 末尾の"忘れ去られた"フリーブロックと連接しなかった。
;
MEMHEAD STRUC
using dw ?
nextseg dw ?
mem_id dw ?
MEMHEAD ENDS
func HMEM_ALLOCBYTE ; hmem_allocbyte() {
push BX
mov BX,SP
;
bytesize = (RETSIZE+1)*2
mov BX,SS:[BX+bytesize]
add BX,15
rcr BX,1
shr BX,1
shr BX,1
shr BX,1
jmp short hmem_allocb
endfunc ; }
func HMEM_ALLOC ; hmem_alloc() {
push BX
mov BX,SP
;
parasize = (RETSIZE+1)*2
mov BX,SS:[BX+parasize]
hmem_allocb:
cmp mem_TopSeg,0 ; house keeping
jne short A_S
call MEM_ASSIGN_ALL
A_S:
push CX
push ES
test BX,BX
jz short NO_MEMORY ; house keeping
mov AX,mem_OutSeg
sub AX,mem_EndMark
cmp BX,AX
jae short NO_MEMORY ; house keeping (add 95/3/19)
inc BX
mov AX,mem_FirstHole
test AX,AX
jz short ALLOC_CENTER ; 中心から取るのね
; フリーブロックから探す
SEARCH_HOLE_S:
mov CX,mem_OutSeg
SEARCH_HOLE:
mov ES,AX
mov AX,ES:[MEMHEAD.nextseg]
cmp ES:[MEMHEAD.using],0
jne short SEARCH_HOLE_E
mov CX,ES
add CX,BX
jc short SEARCH_HOLE_E0 ; 95/3/22
cmp CX,AX ; now+size <= next
jbe short FOUND_HOLE
SEARCH_HOLE_E0:
mov CX,mem_OutSeg
SEARCH_HOLE_E:
cmp AX,CX
jne short SEARCH_HOLE
; フリーブロックにはめぼしいものはなかった
ALLOC_CENTER:
; 中心から確保するのね
mov AX,mem_TopHeap
mov CX,AX
sub AX,BX
jc short NO_MEMORY ; 95/3/22
cmp AX,mem_EndMark
jb short NO_MEMORY
mov mem_TopHeap,AX
mov ES,AX
mov ES:[MEMHEAD.nextseg],CX
mov ES:[MEMHEAD.using],1
mov BX,AX
jmp short RETURN
NO_MEMORY: ; こんなとこに
mov AX,0
mov mem_AllocID,AX
stc
pop ES
pop CX
pop BX
ret 2
; ES=now
; AX=next
; CX=now+size
FOUND_HOLE:
; いいフリーブロックが見つかったので
; 前の必要部分だけを切り取るのだ
sub AX,CX
cmp AX,1 ; 新しい穴が 0〜1パラの大きさしかないなら穴を占有する
jbe short JUST_FIT
add AX,CX
mov ES:[MEMHEAD.using],1
mov ES:[MEMHEAD.nextseg],CX
mov BX,ES
mov ES,CX
mov ES:[MEMHEAD.nextseg],AX
mov ES:[MEMHEAD.using],0
cmp BX,mem_FirstHole
jne short RETURN
mov mem_FirstHole,CX ; 今のが先頭フリーブロックだったら更新だ
jmp short RETURN
; ちょうどいい按配でフリーブロックが見つかったのね
JUST_FIT:
mov ES:[MEMHEAD.using],1
mov BX,ES
cmp BX,mem_FirstHole
jne short RETURN
; 今つぶしたのが先頭フリーブロックだったのなら検索だ
mov AX,mem_OutSeg
mov CX,BX
push BX
SEARCH_NEXT_HOLE:
les CX,ES:[0] ; CX=using, ES=nextseg
jcxz short FOUND_NEXT_HOLE
mov BX,ES
cmp BX,AX
jb short SEARCH_NEXT_HOLE
xor BX,BX
FOUND_NEXT_HOLE:
mov mem_FirstHole,BX
pop BX
; jmp short RETURN
; in: BX = 確保できたメモリの管理ブロックのsegment
RETURN: mov ES,BX
mov AX,0
xchg AX,mem_AllocID
mov ES:[MEMHEAD.mem_id],AX
lea AX,[BX+1]
clc
NO_THANKYOU: ; hmem_freeのエラーはここにくる(笑)
pop ES
pop CX
pop BX
ret 2
endfunc ; }
func HMEM_FREE ; hmem_free() {
push BX
mov BX,SP
push CX
push ES
;
memseg = (RETSIZE+1)*2
mov BX,SS:[BX+memseg]
dec BX
mov ES,BX
cmp BX,mem_TopHeap
je short EXPAND_CENTER ; 先頭のブロックなら専用処理へ
jb short NO_THANKYOU ; mem_TopHeapより小さいなら無効
; 先頭ではないブロックの開放処理
xor BX,BX
cmp ES:[BX].MEMHEAD.using,1
jne short NO_THANKYOU ; usingが1でなければ無効
mov ES:[BX].MEMHEAD.using,BX ; using <- 0
mov CX,mem_FirstHole
mov AX,ES
mov mem_FirstHole,AX
jcxz short FREE_RETURN ; 穴がなかったのならすぐOKだ
cmp AX,CX
jb short CONNECT_START
mov AX,CX ; 以前の最初の穴と現在位置のどちらか低い方を
mov mem_FirstHole,AX ; 新しい最初の穴に。
CONNECT_START:
mov CX,AX
mov AX,ES:[BX].MEMHEAD.nextseg ; 終了地点は、目的ブロックの次だけど
cmp AX,mem_OutSeg
jne short NO_TAIL
mov AX,ES ; 末尾だったら、終了地点をひとつ前へ
NO_TAIL:
; ・連接してしまったフリーブロックを接続する作業
push DS
CONNECT_FREE:
; 空きを探すループ
mov DS,CX ; DS<-CX
mov CX,[BX].MEMHEAD.nextseg ; CX=next seg
cmp CX,AX
ja short CONNECT_SKIP_OVER ; nextsegが最終segより大きければ終わり
cmp [BX].MEMHEAD.using,BX
jne short CONNECT_FREE ; フリーブロックになるまで進める
; 連続した空きを繋ぐループ
CONNECT_FREE2:
mov ES,CX ; ES<-CX(=next seg)
cmp ES:[BX].MEMHEAD.using,BX ; 連接したフリーまで進める
jne short CONNECT_FREE
; DSとESのフリーブロックが連接している
mov CX,ES:[BX].MEMHEAD.nextseg ; CX=新しいnext seg
mov [BX].MEMHEAD.nextseg,CX ; 接続
cmp CX,AX
jbe short CONNECT_FREE2 ; CXが最終seg以内ならまた次を見る
CONNECT_SKIP_OVER:
pop DS
jmp short FREE_RETURN
EVEN
EXPAND_CENTER: ; 先頭ブロックの開放
xor BX,BX
mov AX,ES:[BX].MEMHEAD.nextseg
mov mem_TopHeap,AX
cmp AX,mem_OutSeg
je short FREE_RETURN ; 末尾だったら終り
mov ES,AX
cmp ES:[BX].MEMHEAD.using,BX
jne short FREE_RETURN ; 次のブロックが使用中なら終り
; すぐ次(ES:)がフリーブロックなのでそこも詰める。
mov AX,ES:[BX].MEMHEAD.nextseg
mov mem_TopHeap,AX
; 以後の最初のフリーブロックを検索し、その場所をmem_FirstHoleに入れる
mov CX,mem_OutSeg
cmp AX,CX
je short FREE_LOST_HOLE ; それが最終ブロックなら飛ぶ
jmp short X_SEARCH_HOLE
EVEN
X_SEARCH_NEXT_HOLE:
mov AX,ES:[BX].MEMHEAD.nextseg
cmp AX,CX
je short FREE_LOST_HOLE
X_SEARCH_HOLE:
mov ES,AX
cmp ES:[BX].MEMHEAD.using,BX
jne short X_SEARCH_NEXT_HOLE
mov BX,ES
FREE_LOST_HOLE:
mov mem_FirstHole,BX
FREE_RETURN:
clc
pop ES
pop CX
pop BX
ret 2
endfunc ; }