在汇编中通过 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
只是 CX
和 DX
形成的 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;
我想通过中断 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
只是 CX
和 DX
形成的 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;