mirror of https://github.com/nmlgc/ReC98.git
310 lines
7.6 KiB
NASM
310 lines
7.6 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:[0].nextseg
|
|||
|
cmp ES:[0].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:[0].nextseg,CX
|
|||
|
mov ES:[0].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:[0].using,1
|
|||
|
mov ES:[0].nextseg,CX
|
|||
|
mov BX,ES
|
|||
|
mov ES,CX
|
|||
|
mov ES:[0].nextseg,AX
|
|||
|
mov ES:[0].using,0
|
|||
|
cmp BX,mem_FirstHole
|
|||
|
jne short RETURN
|
|||
|
mov mem_FirstHole,CX ; 今のが先頭フリーブロックだったら更新だ
|
|||
|
jmp short RETURN
|
|||
|
|
|||
|
; ちょうどいい按配でフリーブロックが見つかったのね
|
|||
|
JUST_FIT:
|
|||
|
mov ES:[0].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:[0].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].using,1
|
|||
|
jne short NO_THANKYOU ; usingが1でなければ無効
|
|||
|
mov ES:[BX].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].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].nextseg ; CX=next seg
|
|||
|
cmp CX,AX
|
|||
|
ja short CONNECT_SKIP_OVER ; nextsegが最終segより大きければ終わり
|
|||
|
cmp [BX].using,BX
|
|||
|
jne short CONNECT_FREE ; フリーブロックになるまで進める
|
|||
|
; 連続した空きを繋ぐループ
|
|||
|
CONNECT_FREE2:
|
|||
|
mov ES,CX ; ES<-CX(=next seg)
|
|||
|
cmp ES:[BX].using,BX ; 連接したフリーまで進める
|
|||
|
jne short CONNECT_FREE
|
|||
|
; DSとESのフリーブロックが連接している
|
|||
|
mov CX,ES:[BX].nextseg ; CX=新しいnext seg
|
|||
|
mov [BX].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].nextseg
|
|||
|
mov mem_TopHeap,AX
|
|||
|
cmp AX,mem_OutSeg
|
|||
|
je short FREE_RETURN ; 末尾だったら終り
|
|||
|
mov ES,AX
|
|||
|
cmp ES:[BX].using,BX
|
|||
|
jne short FREE_RETURN ; 次のブロックが使用中なら終り
|
|||
|
|
|||
|
; すぐ次(ES:)がフリーブロックなのでそこも詰める。
|
|||
|
mov AX,ES:[BX].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].nextseg
|
|||
|
cmp AX,CX
|
|||
|
je short FREE_LOST_HOLE
|
|||
|
X_SEARCH_HOLE:
|
|||
|
mov ES,AX
|
|||
|
cmp ES:[BX].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 ; }
|