mirror of https://github.com/nmlgc/ReC98.git
310 lines
7.8 KiB
NASM
310 lines
7.8 KiB
NASM
; 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 ; }
|