Assembly 汇编x86(16位):更精确的时间测量

Assembly 汇编x86(16位):更精确的时间测量,assembly,time,dos,x86-16,tasm,Assembly,Time,Dos,X86 16,Tasm,我正在用DOSBox用TASM 16位编程,今天的问题是: 使用DOS INT 21h/2Ch,我可以获得系统当前的百分之一秒。 这很好,所有的。。。直到它不是 看,我在寻找一个以毫秒为单位的至少半精确的时间测量,我肯定这是可能的 为什么,你问?看一看。 使用此中断,我可以将程序延迟微秒。 如果存在这样的精确性,我敢肯定获得毫秒数将是在公园里散步 我有一些想法:使用每1/1024秒发生一次的时间,但我不知道如何收听中断,我也不想要一个不能除以10的计时系统 到目前为止,这个问题已经占据了我的上风

我正在用DOSBox用TASM 16位编程,今天的问题是: 使用DOS INT 21h/2Ch,我可以获得系统当前的百分之一秒。 这很好,所有的。。。直到它不是

看,我在寻找一个以毫秒为单位的至少半精确的时间测量,我肯定这是可能的

为什么,你问?看一看。 使用此中断,我可以将程序延迟微秒。 如果存在这样的精确性,我敢肯定获得毫秒数将是在公园里散步

我有一些想法:使用每1/1024秒发生一次的时间,但我不知道如何收听中断,我也不想要一个不能除以10的计时系统

到目前为止,这个问题已经占据了我的上风,我无法在网上找到已经存在的解决方案


提前干杯。

非常感谢Peter Cordes在评论中的回答,我现在将答案发布给任何打算使用30年前的老式编译器的人

粗略地说,16位TASM中最好的时钟仍然不够精确。 幸运的是,在TASM中,您可以使用
.386
指令(如上所述)来“解锁”32位模式

然后,您可以使用
RDTSC
命令(读取时间戳计数器),但有一个问题。。它在TASM中不存在。 它不存在的事实对我们没有任何意义,因为所有命令都在TASM(通常称为助记符)中,只是操作码的替代品,操作码定义了CPU可以运行的每一条指令

英特尔奔腾CPU发布时,包含了RDTSC的操作码,因此,如果您从中获得了CPU,那么。。。你很好

现在,如果RDTSC指令在TASM中不存在,我们如何运行它?(但在我们的CPU中)

在TASM中,有一条名为
db
的指令,我们可以用它直接运行操作码

如图所示,运行RDTSC需要做的是:
db0fh,31h


就这样!现在,您可以轻松地运行此指令,并且您的程序仍将保持混乱状态,但时间混乱

在16位PC兼容的x86系统中,PIT(可编程间隔计时器)使用1.19318MHz的时钟输入来减少16位计数器。每当计数器在216=65536增量后环绕时,就会生成一个中断。BIOS提供的ISR(中断服务程序)处理它,然后以1.19318MHz/65536~=18.2 Hz的频率递增软件计数器

在DOS和其他实模式操作系统下,16位PIT计数器可以在两个8位块中直接从相关端口读取,该数据可以与软件维护的滴答计数器结合,以实现毫秒分辨率。基本上,一个使用48位滴答计数器,其中BIOS维护的32位软件计数器构成最高有效位,16位PIT计数器构成最低有效位

由于数据不是一下子全部读出的,因此存在必须适当处理的比赛条件的风险。此外,一些生物传感器将PIT编程为方波发生器,而不是简单的速率计数器。虽然这不会干扰增加软件刻度的任务,但会干扰PIT计数器寄存器与软件刻度的直接组合。这需要对PIT进行一次性初始化,以确保其在速率计数模式下运行

下面是16位汇编代码,包装成一个Turbo-Pascal单元,我多年来一直使用它来实现毫秒精度的健壮计时。这里从滴答计数到毫秒的转换有点像黑匣子。我丢失了它的设计文档,现在无法快速地重建它。我记得这个定点计算的抖动小到可以可靠地测量毫秒。Turbo Pascal的调用约定要求在
DX:AX
寄存器对中返回32位整数结果

单位时间;{版权所有(c)1989-1993 Norbert Juffa}
接口
功能时钟:长时钟;{与虚拟机相同;时间(毫秒)}
实施
功能时钟:长时钟;汇编程序;
ASM
推送DS{保存调用方的数据段}
MOV DS,Seg0040{访问股票计数器}
MOV BX,6Ch{segm中股票计数器的偏移量。}
MOV DX,43h{定时器芯片控制端口}
MOV AL,4{冻结计时器0}
PUSHF{保存调用方的int标志设置}
CLI{使读取计数器成为原子操作}
MOV DI,DS:[BX]{读取BIOS计数器}
MOV CX,DS:[BX+2]
STI{启用股票行情计数器更新}
输出DX,AL{锁存计时器0}
CLI{使读取计数器成为原子操作}
MOV SI,DS:[BX]{读取BIOS计数器}
MOV BX,DS:[BX+2]
在AL中,40h{读取锁存定时器0 lo字节}
MOV-AH,AL{save-lo-byte}
在AL中,40h{读取锁存计时器0 hi字节}
POPF{还原调用方的int标志}
XCHG AL,AH{hi和lo的正确顺序}
CMP DI,SI{股票行情计数器已更新?}
JE@no_更新{no}
或AX,AX{在计时器冻结之前更新?}
JNS@no_update{no}
MOV DI,SI{使用第二个}
MOV CX,BX{股票计数器}
@无更新:非AX{计数器倒计时}
MOV BX,36EDh{负载倍增器}
MUL BX{W1*M}
MOV-SI