在汇编中通过 BIOS 中断获取系统时间

Get system time with BIOS interrupt in assembly

我想通过中断 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获取时钟?我应该读入一个变量吗?

不要使用那个中断,改用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

看来 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 位 x 16 位乘法例程,您可以乘以 floor((2^32)/除数),之后只需要一个减法检查。

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;