首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

DOS 時代組合語言經典原始碼賞析:BURNOUT 螢幕保護裝置控制程式

     編輯:組合語言

前言

本文收錄 BURNOUT.ASM (CJ Dunford, 1985),功能為讀取/設定螢幕保護裝置 (burnout device) 參數:空閒時間 (ticks)、硬體/軟體消隱模式、視訊監控開關。透過字元裝置驅動程式介面 (INT 21h AH=3Dh/3Fh/40h 操作裝置檔案 BRNDEV) 實現,支援命令列參數解析、裝置 I/O 刷新/執行命令協定。展示了 DOS 字元裝置驅動架構、裝置命令協定、參數解析技巧、.COM 程式結構。

程式功能與用法

BURNOUT [ticks] [C+-] [V+-] [H+-]
參數可用任意分隔符
無參數:顯示目前狀態
範例:
 burnout 5000           ; 設定空閒 5000 ticks
 burnout 5000H+         ; 5000 ticks + 硬體消隱
 burnout c+h-v+         ; 持續清除 + 軟體消隱 + 監控視訊
 burnout /C+ /H- /V+    ; 同前
 burnout                ; 僅顯示狀態

核心架構:字元裝置驅動程式介面

DOS 中字元裝置 (如 CON, AUX, PRN, 自訂 BRNDEV) 以檔案介面存取:

  1. INT 21h AH=3Dh (OPEN) 開啟裝置名稱 → 取得控制代碼
  2. INT 21h AH=40h (WRITE) 向裝置發送資料/命令
  3. INT 21h AH=3Fh (READ) 從裝置讀取狀態/資料
  4. INT 21h AH=3Eh (CLOSE) 關閉控制代碼

BRNDEV 定義雙字元協定:

  • '@' (40h):Flush - 刷新待處理 I/O
  • '#' (23h):Execute - 執行先前寫入的參數命令

完整原始碼

COMMENT *
 Demo (and semi-useful) program to read/set burnout device parameters.
 Usage: burnout [ticks] [C+-] [V+-] [H+-]
 Parameters can be separated by almost anything.
 With no parameters, program simply returns current status.
 Examples:
 burnout 5000 (sets time to 5000 ticks)
 burnout 5000H+ (time=5000, use hardware blanking)
 burnout 5000,h+ (ditto, separators don't matter)
 burnout c+h-v+ (continuous clear, software, monitor video)
 burnout /C+ /H- /V+ (ditto)
 burnout (return status only)
 Assembly/link:
 masm burnout;
 link burnout; (ignore NO STACK warning message)
 exe2bin burnout burnout.com
 By CJDunford 20-Mar-1985
 Compuserve 76703,2002
======================================================================
*
stdout equ 1
stderr equ 2
DOS equ 21H
TERMINATE equ 20H
PRINT equ 09H
FOPEN equ 3D02H
FREAD equ 3FH
FWRITE equ 40H
CR equ 13
LF equ 10

code segment
assume cs:code,ds:code
org 80H
ParmLength label byte
org 81H
Parameters label byte
org 100H
main proc far
 jmp start
DevName db 'BRNDEV',0
handle dw ?
Flush db '@'
Execute db '#'
NotInstalled db 'Burnout device is not installed',13,10
NotInstalledL equ $ - NotInstalled
Status db 'Current status: '
StatInsert db 40 dup (?)
start:
 mov dx,offset DevName
 mov ax,FOPEN
 int DOS
 jnc A1
 mov bx,stderr
 mov cx,NotInstalledL
 mov dx,offset NotInstalled
 mov ah,FWRITE
 int DOS
 jmp exit
A1:
 mov handle,ax
 mov dx,offset Flush
 mov cx,1
 mov bx,handle
 mov ah,FWRITE
 int DOS
 mov cl,ParmLength
 or cl,cl
 jz A2
 xor ch,ch
 mov dx,offset Parameters
 mov bx,handle
 mov ah,FWRITE
 int DOS
 mov dx,offset Execute
 mov cx,1
 mov bx,handle
 mov ah,FWRITE
 int DOS
A2:
 mov dx,offset StatInsert
 mov cx,0FFH
 mov bx,handle
 mov ah,FREAD
 int DOS
 mov cx,ax
 mov di,offset StatInsert
 add di,cx
 mov al,CR
 cld
 stosb
 mov al,LF
 stosb
 mov al,'$'
 stosb
 mov dx,offset Status
 mov ah,PRINT
 int DOS
exit:
 int TERMINATE
main endp
code ends
end main

關鍵技術解析

1. PSP 參數區存取

org 80H
ParmLength label byte   ; PSP:80h = 參數長度
org 81H
Parameters label byte   ; PSP:81h = 參數字串起始
org 100H                ; .COM 程式入口點

直接對應 PSP (Program Segment Prefix) 結構,無需呼叫 DOS API 取得命令列。

2. 裝置開啟與錯誤處理

mov dx,offset DevName  ; 'BRNDEV',0
mov ax,FOPEN (3D02h)   ; 開啟模式:讀/寫
int DOS
jnc A1                 ; CF=0 成功
; 失敗:寫入 STDERR (BX=2) 顯示錯誤訊息
mov bx,stderr
mov cx,NotInstalledL
mov dx,offset NotInstalled
mov ah,FWRITE
int DOS
jmp exit

裝置名稱以 0 結尾 (ASCIIZ),FOPEN=3D02h 合併 AH=3Dh, AL=02h (讀/寫模式)。

3. 命令發送協定

; 1. Flush 待處理 I/O
mov dx,offset Flush  ; '@'
mov cx,1
mov bx,handle
mov ah,FWRITE
int DOS

; 2. 發送參數字串 (若有)
mov cl,ParmLength
or cl,cl
jz A2
xor ch,ch            ; CX = 參數長度
mov dx,offset Parameters
mov bx,handle
mov ah,FWRITE
int DOS

; 3. Execute 命令
mov dx,offset Execute ; '#'
mov cx,1
mov bx,handle
mov ah,FWRITE
int DOS

先 @ 刷新,再寫入參數,最後 # 觸發裝置端解析執行。參數字串原樣傳遞,解析邏輯在裝置驅動程式端。

4. 狀態讀取與顯示

mov dx,offset StatInsert
mov cx,0FFH          ; 要求最多 255 位元組
mov bx,handle
mov ah,FREAD
int DOS
mov cx,ax            ; 實際讀取位元組數
mov di,offset StatInsert
add di,cx
mov al,CR; stosb     ; 追加 CR/LF/$ 供 DOS 列印功能 (AH=09h) 使用
mov al,LF; stosb
mov al,'$'; stosb
mov dx,offset Status
mov ah,PRINT
int DOS

裝置驅動程式將狀態字串寫入 StatInsert 緩衝區,程式補上 CR/LF/$ 後用 AH=09h 列印。

現代對應與啟發

BURNOUT 技術現代對應
字元裝置驅動檔案介面Linux /dev/xxx、Windows \\.\DeviceName、DeviceIoControl
裝置命令協定 (@/#)IOCTL 碼、ioctl()、DeviceIoControl 控制碼
PSP 參數區直接存取GetCommandLine/__argv/argc/argv
標準錯誤輸出錯誤訊息stderr/fprintf(stderr,...)/Console.Error
.COM 純二進位映像 (exe2bin)原生二進位、GOOS=linux GOARCH=amd64 go build

學習重點

  • DOS 字元裝置驅動程式的檔案介面抽象:OPEN/READ/WRITE/CLOSE 統一存取
  • 裝置端協定設計:Flush 緩衝 → 寫入參數 → Execute 觸發 三階段,避免競態
  • PSP 結構活用:80h/81h/100h 固定偏移,零 API 開銷
  • 極簡錯誤處理:開啟失敗 → STDERR 訊息 → INT 20h 退出
  • .COM 格式:ORG 100h、單段、exe2bin 轉換、無重定位項

總結

BURNOUT.ASM 展示了使用者程式透過標準檔案 API 控制硬體裝置驅動程式的經典模式:開啟裝置名稱、發送命令序列、讀取狀態回應。這種「一切皆檔案」的抽象在 Unix/Linux (/dev) 和 Windows (CreateFile(\\.\Device)) 中延續至今。程式本身極精簡 (約 80 行),卻涵蓋PSP 參數存取、裝置 I/O 協定、錯誤處理、狀態查詢完整閉環,是理解「裝置驅動介面程式設計」的最佳入門範例之一。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved