【问题标题】:Get system time with BIOS interrupt in assembly通过汇编中的 BIOS 中断获取系统时间
【发布时间】:2017-04-27 14:04:21
【问题描述】:

我想通过中断 INT 1Ah/AH = 00h 获取时间(小时、分钟、秒)。我知道它在 CX 中保留时钟计数的高位部分,在 DX 中保留时钟计数的低位部分。

我搜索了一下,发现以下公式将时钟计数转换为 时间:

                             Hour      = Clock / 65543 (1007h)
                             Remainder = Clock MOD 65543

                             Minutes   = Remainder / 1092 (444h)
                             Remainder = Remainder MOD 1092

                             Second    = Remainder / 18.21
                             Remainder = Remainder MOD 18.21

但是我对如何使用它们感到困惑,如何从 CX 和 DX 获取时钟?我应该读入一个变量吗?

【问题讨论】:

    标签: assembly interrupt bios emu8086 systemtime


    【解决方案1】:

    不要使用那个中断,而是使用INT 1Ah/02。如果您坚持,请注意Clock 只是由CXDX 形成的32 位值。将它们放入变量中根本不会帮助您。由于您需要对其进行除法,而DIV 指令期望在DX(高)和AX(低)中得到红利,您只需稍微调整一下即可。但是,除以18.21 时会遇到问题。像这样的东西可以工作,但请注意常量1092 也不准确。如果你运气不好,你可能会在几分钟内得到60(如果clock mod 65543恰好高于65519,除以1092将得到60。)

    mov ax, dx           ; low 16 bits
    mov dx, cx           ; high 16 bits
    div word [mem_65543] ; constant in memory
    mov [hours], ax
    mov ax, dx           ; work with remainder
    xor dx, dx           ; zero top bits
    div word [mem_1092]  ; constant in memory
    mov [minutes], ax
    mov ax, [mem_100]    ; constant in memory
    mul dx               ; scale by 100
    div word [mem_1821]  ; constant in memory
    mov [seconds], ax
    

    【讨论】:

    • 我尝试了 INT 1Ah/02,但出现错误:“INT 1Ah,AH=02h - 尚不支持。请参阅支持的中断列表” - 我正在使用 emu8086。
    • 为什么最后除以 100 ("scale back") ?秒数已经在AX 寄存器中。
    • @Jester 谢谢。为什么常量和小时、分钟、秒有 [] 括号?另外,我应该将它们声明为 db 吗?
    • 这只是正确的英特尔语法。您可能正在使用不需要它的汇编程序。不,这些必须是文字,所以dw
    • 呃,65543 当然不止一个词,耶!没发现。
    【解决方案2】:

    EMU8086 似乎正在模拟 8254 计时器 0,大多数 PC 系统仍在模拟,以下是计时值:

        8254 channel 0 runs at 1.19318 mhz or ~ 838.0965 nsecs / cycle
        System timer interrupts every 65536 cycles ~= 54.9255 ms
        or ~ 18.20648 ticks per second
        1 ms   = 1193.18 cycles
        1 hour ~= 65543 ticks ~= 3599.9816 secs
       24 hour ~= 1573040 (hex 1800B0) ticks ~= 86399.998 secs
    

    用于将刻度精确转换为小时/分钟/秒(截断)的示例 C 代码:

        i = itick<<10;             /* itick * 1024 */
        hour = 0;
        while(i >= 67116375){
            hour++;
            i -= 67116375;
        }
        i <<= 4;                   /* itick * 16384 */
        minute = 0;
        while(i >= 17897700){
            minute++;
            i -= 17897700;
        }
        second = 0;
        while(i >= 298295){
            second++;
            i -= 298295;
        }
    

    使用 32 位乘 16 位乘法例程,您可以乘以 floor((2^32)/divisor),之后只需进行一次减法检查。

    uint32_t i, tick, hour, minute, second;
    /* ... */
        i = tick<<10;
        hour = (uint32_t)(((uint64_t)i*63)>>32);
        i -= hour*67116375;
        if(i >= 67116375){
            hour++;
            i -= 67116375;
        }
        i <<= 4;
        minute = (uint32_t)(((uint64_t)i*239)>>32);
        i -= minute*17897700;
        if(i >= 17897700){
            minute++;
            i -= 17897700;
        }
        second = (uint32_t)(((uint64_t)i*14398)>>32);
        i -= second*298295;
        if(i >= 298295){
            second++;
            i -= 298295;
        }
    

    使用 32 x 32 位乘法例程,可以消除单减法检查:

        i = tick<<10;
        hour = (uint32_t)(((uint64_t)i*2147243323u)>>57);
        i -= hour*67116375;
        i <<= 4;
        minute = (uint32_t)(((uint64_t)i*4026081231u)>>56);
        i -= minute*17897700;
        second = (uint32_t)(((uint64_t)i*1887225577u)>>49);
        i -= second*298295;
    

    【讨论】:

      猜你喜欢
      • 2019-09-25
      • 2014-07-23
      • 1970-01-01
      • 2022-07-11
      • 2013-06-22
      • 2012-07-07
      • 2010-09-24
      • 2011-08-02
      • 1970-01-01
      相关资源
      最近更新 更多