解釋型/編譯型 BASIC (GW-BASIC, QuickBASIC) 內建指令有限,無法直接查詢磁碟剩餘空間。GETSPACE.ASM 實作一個 FAR PROC 供 BASIC 以 CALL GETSPACE(ah, al, bh, bl, ch, cl) 呼叫 (6 個整數參數傳址),內部呼叫 INT 21h, AH=36h 取得磁碟資訊,將結果回填至參數變數。程式展示了 BASIC 參數傳址慣例 (String Descriptor 結構)、DOS 磁碟空間查詢、十六進位轉十進位 ASCII 字串、結果回填等完整流程。
BASIC 傳遞 **變數描述子** 位址 (非直接值)。整數變數描述子結構:
; SS:[BP+6] 參數 1 (CL) 描述子位址 ; 描述子結構: [類型標誌:WORD][資料位址:DWORD] (近指標模式下段值隱含在 DS) ; 實際資料位址 = DS:[描述子+2]程式以
MOV BX, [BP+6] / MOV DI, [BX+2]取得參數變數在 BASIC 資料區的位址 (DI),再MOV ES:[DI], AX寫入結果。核心流程
- 建立資料區定址:
PUSH DS/ES / MOV AX, datarea / MOV DS, AX切換至本地資料段。- 取得驅動器代號:從參數 6 (
CL) 讀取驅動器號 (0=預設, 1=A, 2=B...),存入DL。- 呼叫 DOS 36h:
MOV AH, 36h / INT 21h,回傳:
AX= 每叢集扇區數 (0xFFFF = 錯誤)BX= 可用叢集數CX= 每扇區位元組數DX= 總叢集數- 結果封裝回參數:將
AH, AL, BH, BL, CH, CL分別存入對應參數位址 (低位元組)。- 十六進位轉十進位字串 (HEXTODEC):對
DX:AX(32 位元無號整數) 反覆除以 10,餘數轉 ASCII 存入參數 1 緩衝區 (預設 8 字元空白預填)。- 恢復段暫存器並返回:
POP ES/DS/BP / RET 12(清除 6 個參數,每個 2 位元組)。關鍵程式碼片段
1. 參數存取與 DOS 呼叫
push bp sub ax, ax mov si, ss:[bp+6] ; 參數 6 (CL) 描述子位址 mov al, es:[si] ; 取得驅動器代號 mov dx, ax ; DL = 驅動器 mov ah, 36h ; Get Free Space int 21h2. 結果拆解至區域變數
xchg dx, ax sub ax, ax xchg dx, ax ; DX=0, AX=原 AX (扇區/叢集) mov dl, ah mov ah_ret, dx ; AH mov dl, al mov al_ret, dx ; AL mov dl, bh mov bh_ret, dx ; BH mov dl, bl mov bl_ret, dx ; BL mov dl, ch mov ch_ret, dx ; CH mov dl, cl mov cl_ret, dx ; CL3. 回填參數 (逆序對應 BASIC 堆疊順序)
mov ax, cl_ret mov si, ss:[bp+6] mov es:[si], ax ; 回填 CL mov ax, ch_ret mov si, ss:[bp+8] mov es:[si], ax ; 回填 CH ... (BL, BH, AL, AH 同理) ...4. HEXTODEC: 32 位元無號整數轉十進位 ASCII
HEXTODEC: mov si, 10 push ax mov ax, dx xor dx, dx div si ; DX:AX / 10 → AX=商, DX=餘數 pop cx push ax mov ax, cx div si pop si or dl, 30h ; 餘數轉 ASCII mov byte ptr [di], dl dec di xchg dx, si or ax, ax jnz HEXTODEC巧妙利用
SI暫存除數 10,CX暫存高位商,交替處理高低 16 位,實現 32 位除法 (8086 無 32 位除法指令)。完整原始碼
get_spa equ 36h
doscall equ 21h
dgroup group datarea
datarea segment para public 'DATA'
ah_ret dw ?
al_ret dw ?
bh_ret dw ?
bl_ret dw ?
ch_ret dw ?
cl_ret dw ?
datarea ENDS
cseg segment 'CODE'
assume cs:cseg
public frespace
frespace proc far
push bp
mov bp,sp
push ds
push es
mov ax,datarea
mov ds,ax
assume ds:datarea
push bp
sub ax,ax
mov si,ss:[bp+6]
mov al,es:[si]
mov dx,ax
mov ah,get_spa
int doscall
xchg dx,ax
sub ax,ax
xchg dx,ax
mov dl,ah
mov ah_ret,dx
mov dl,al
mov al_ret,dx
mov dl,bh
mov bh_ret,dx
mov dl,bl
mov bl_ret,dx
mov dl,ch
mov ch_ret,dx
mov dl,cl
mov cl_ret,dx
pop bp
mov ax,cl_ret
mov si,ss:[bp+6]
mov es:[si],ax
mov ax,ch_ret
mov si,ss:[bp+8]
mov es:[si],ax
mov ax,bl_ret
mov si,ss:[bp+10]
mov es:[si],ax
mov ax,bh_ret
mov si,ss:[bp+12]
mov es:[si],ax
mov ax,al_ret
mov si,ss:[bp+14]
mov es:[si],ax
mov ax,ah_ret
mov si,ss:[bp+16]
mov es:[si],ax
pop es
pop ds
pop bp
ret 12
frespace endp
cseg ends
end教學價值
GetDiskFreeSpace 的前身。HEXTODEC 以 16 位元 DIV 指令模擬 32 位元除法,展示無硬體支援時的多精度運算技巧。PUSH DS/ES / MOV DS, 本地段 / ... / POP ES/DS 確保不污染 BASIC 執行期環境。GETSPACE 以約 100 行程式碼,完整串聯「高階語言介面 → 參數解析 → 系統呼叫 → 多精度運算 → 結果編碼 → 參數回填 → 環境恢復」全鏈路,是學習 DOS 時代混合語言程式設計、系統服務封裝的經典教材。