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

BIOS 定時器計數轉時間格式:TSR 時鐘程式核心演算法分析

     編輯:組合語言

前言

文章分析一個 TSR 時鐘程式中,將 BIOS 資料區 (0040h:006Ch/006Eh) 的 32 位元定時器計數值轉換為「HH:MM:SS」 ASCII 字串的核心子程式。作者詳細追蹤暫存器變化,並對計數器最大值 (0x1800B0) 與理論值 (86400 秒) 的差異提出疑問。

BIOS 定時器資料結構

  • 位址:0040h:006Ch (低字) / 0040h:006Eh (高字),共 32 位元
  • 更新頻率:INT 1Ch 每 55 毫秒觸發一次 (約 18.1818 Hz)
  • 最大計數:0x001800B0 = 1,573,040
  • 理論一天計數:86,400 秒 × 18.1818 ≈ 1,572,480 (差 560)

轉換子程式完整追蹤

HMS db 8 dup(':')  ; 輸出緩衝區 "::::::::"

time proc
 lea di, position   ; (1) DI 指向 HMS
 mov ax,0; mov ds,ax ; (2-3) DS=0 (BIOS 資料區段)
 mov al,ds:[46eh]    ; (4) AL = 高字 (小時計數)
 call clk1           ; (5) 轉換小時 → ASCII
 mov ax,ds:[46ch]    ; (6) AX = 低字 (總滴答數)
 mov dx,0; mov bx,444h ; (7-8) DX=0, BX=1092 (444h)
 call clk0           ; (9) 轉換分鐘
 mov ax,dx; mov cx,3ch ; (10-11) AX=餘數, CX=60
 mul cx              ; (12) AX = 餘數 * 60
 clk0:
 add di,3            ; (13) DI 移至下一欄位
 div bx              ; (14) AX/DX = AX/1092
 clk1:
 aam                 ; (15) AL→AH=商, AL=餘數 (BCD)
 add ax,3030h        ; (16) 轉 ASCII '0'-'9'
 xchg ah,al          ; (17) 交換高低位 (十位在前)
 mov cs:[di],ax      ; (18) 存入 HMS
 ret                 ; (19)
time endp

演算法邏輯解析

第一階段:小時 (高字直接轉換)

  • AL = [0040:006E] = 高字 = 總滴答數 / 65536
  • 因 65536 滴答 ≈ 3600 秒 = 1 小時,高字直接對應小時數 (0-23)
  • CLK1:AAM → BCD 碼 → ASCII → 交換位序 → 存入 HMS[0:1]

第二階段:分鐘 (低字除以 1092)

  • AX = [0040:006C] = 低字 = 總滴答數 % 65536
  • DIV BX (1092):1092 滴答 = 60 秒 (1092/18.2 = 60)
  • 商 AX = 分鐘數 (0-59),餘數 DX = 分鐘內滴答數
  • CLK0 接 CLK1 轉換存入 HMS[3:4]

第三階段:秒 (餘數 × 60 / 1092)

  • AX = DX (分鐘餘數),MUL CX (60) → AX = 餘數 * 60
  • 再次 DIV BX (1092):商 = 秒數 (0-59)
  • 原理:(餘數/1092) * 60 = 餘數 * (60/1092) = 餘數 / 18.2 即滴答轉秒
  • 存入 HMS[6:7]

實際執行範例

假設 [006E]=0017h, [006C]=1AA3h (總計 0x00171AA3 = 1,514,147 滴答):

  1. 小時:0x17 = 23 → AAM → 2,3 → ASCII '2','3' → 交換 → '3','2' (註:作者追蹤中 0x17 AAM 得 2,3 似有誤,實為 1,7? 0x17=23, AAM→AH=2,AL=3 正確)
  2. 分鐘:0x1AA3 / 1092 = 6 餘 267 → 分鐘=6 → '0','6'
  3. 秒:267 * 60 / 1092 = 14 餘 ... → 秒=14 → '1','4'
  4. 結果:HMS = "23:06:14" (作者追蹤顯示 "23:06:14",但中間過程文字描述有出入)

作者疑問:計數器最大值差異分析

項目數值說明
最大計數 0x1800B01,573,040BIOS 實際重置值
理論值 (86400×18.1818)1,572,480560 差異 (30.8 秒)
一小時滴答 (3600×18.2)65,520比 65535 少 15
一天滴答 (24×65520)1,572,480同上

結論:BIOS 定時器頻率並非精確 18.2 Hz,而是 1,193,180 Hz / 65,536 = 18.2065 Hz (8253 計數器 16 位元計數器溢位頻率)。
一天滴答 = 86,400 × 18.2065 ≈ 1,573,041 ≈ 0x1800B1,與 0x1800B0 極接近 (差 1)。
作者使用 18.2 近似值導致計算偏差。真實硬體頻率由 1.19318 MHz 晶振除以 65536 決定,非軟體可調。

結語

這段轉換程式碼展示了早期系統程式設計師如何巧妙利用定點運算 (DIV/MUL 定比例) 避免浮點運算,將硬體計數器值高效轉換為人類可讀時間。AAM 指令雖慢但極適合 BCD 轉 ASCII。對於計數器最大值疑問,深入硬體頻率來源 (8253/1.19318 MHz) 即可釐清。這類「硬體頻率 → 軟體計數 → 時間轉換」鏈條,是理解即時系統、嵌入式開發、效能分析的基石知識。

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