Hi, guys! I started to learn assembly just a few months ago. Last time I wrote a small program to compute the CPU frequency, and it worked out. Two weeks later, however, when I recompiled the program, I couldn't get the correct result. It's about 4-5 times less than the actual frequency. Maybe it'll help to paste the code here. I don't know what's the problem. Any suggestion is appreciated.

.586
.model tiny
.code
        org 100h

start:
        lea dx, Message
        mov ah, 9
        int 21h
        cli
init:
        mov bx, 1001
        mov cx, 11
        mov sum, 0
        
wait_for_ref_toggle_1:
        in  al, IOAddr
        bt  ax, REF_TOGGLE
        jnc wait_for_ref_toggle_1

wait_for_ref_toggle_0:
        in al, IOAddr
        bt ax, REF_TOGGLE
        jc wait_for_ref_toggle_0
        
        dec bx                      ; loop 1000 times.
        jnz wait_for_ref_toggle_1
        
        rdtsc
        push eax
        push edx
        mov  bx, 1000
        loop wait_for_ref_toggle_1	; loop 10 times.
        
        pop edx
        pop eax
        mov cx, 10
        
compute_avg_freq:
        pop edi
        pop esi
        sub eax, esi
        sbb edx, edi
        mov ebx, 300000         ; 300000=1000*10*30
        div ebx
        add sum, eax
        mov eax, esi
        mov edx, edi
        loop compute_avg_freq
        
        mov eax, sum
        call dispax


        mov ah, 1 
        int 16h
        jz init

        mov ah, 0
        int 16h
        
exit:
        sti
        mov ah, 4ch 
        int 21h
        
dispc   PROC NEAR
        PUSH AX
        PUSH DX
        MOV AH, 2
        MOV DL, AL
        INT 21H
        POP DX
        POP AX
        RET
dispc   ENDP


dispax  PROC NEAR
        push ax         
        push bx
        push cx
        push dx
        push bp
        mov cx, 5        ; output 5-digit number
        mov bx, 0        ; keep the actual data length
        mov bp, 10       ; display in decimal
disp1:
        xor dx, dx
        div bp
        inc bx           ; increase the data length
        push dx          ; save the reminder
        cmp ax, 0        ; check if the quotient is 0
        jnz disp1
        sub cx, bx
        jle disp3
        mov al, ' '      ; add space to the front if the length does not match
disp2:
        call dispc
        loop disp2
disp3:
        mov cx, bx       ; transfer the actual data length to cx
disp4:
        pop ax
        and al, 0fh
        add al, '0'
        call dispc
        loop disp4
        call SetPos
        pop bp
        pop dx
        pop cx
        pop bx
        pop ax
        ret
dispax  ENDP

SetPos  PROC NEAR		 ; adjust the cursor location
        push ax
        push dx
        push ds
        push cs
        pop ds
        lea dx, Back
        mov ah, 9
        int 21h
        pop ds
        pop dx
        pop ax
        ret
SetPos  ENDP

Even

Message byte 13,10,'Counting CPU speed..., Press any key to STOP !',13,10,13,10
        byte 'Current Cpu Speed:       MHz',8,8,8,8
Back    byte 8,8,8,8,8,'$'

sum			 dword 	 ?
IOAddr		 EQU 	 61H
REF_TOGGLE	 EQU 	 4H

end start

what you do at io port 61h exactly ?

The following code uses BIOS to wait an relative exact amount of time.
You can read rdtsc before and after and calculate value.
If you want program to step faster you can use 100ms instead of 1 second for measurement.
Value for cx:dx then has to be 0186a0h.

mov cx,000fh                    ; wait cx:dx microseconds (0f4240h = 1000000)
        mov dx,4240h
        mov ah,086h
        int BIOS_INT_TSR                ; wait 1 second, (000f4240h microseconds)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.