Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

precision timing

jeffleydajeffleyda Member Posts: 390
what's your favorite way of doing highly accurate timings nowadays?
I was thinking about using the timestamp counter, but then I have to go and calculate the cpu speed. Is there a favorite way of doing that?

since the timestamp gets updated on a per cpu clock, are there issues with clock multipliers and all the other fancy tricks that modern CPUs are doing vs timestamp and cpu speed?

-jeff!

Comments

  • BretBret Member Posts: 114
    : what's your favorite way of doing highly accurate timings nowadays?
    : I was thinking about using the timestamp counter, but then I have to
    : go and calculate the cpu speed. Is there a favorite way of doing
    : that?
    :
    : since the timestamp gets updated on a per cpu clock, are there
    : issues with clock multipliers and all the other fancy tricks that
    : modern CPUs are doing vs timestamp and cpu speed?
    :
    : -jeff!

    For my purposes, I've never needed the precision available using the CPU timestamp counter. I just use the BIOS clock interrupt generator, which has a resolution of approximately 1 microsecond. It requires I/O to get the data, so it is less accurate than getting data from a CPU register. But, it's always been good enough for my purposes up to this point in time. Following is some sample code that I use in some of my programs.

    [code]
    ;------------------------------------------------------------------------------
    ;DELAY FOR A GIVEN NUMBER OF MICROSECONDS
    ;Inputs: AX = number of microseconds to wait (0-65,535)
    ;Outputs:
    ;Changes:
    ; NOTE: Delays will be slightly longer than what's asked for, never shorter.
    ; Accuracy decreases with small delays or slow computers!
    ;------------------------------------------------------------------------------
    DelayUSAX:
    PUSH AX,BX ;Save used registers
    OR AX,AX ;Is there anything to do?
    JZ >D90 ;If not, just quit
    MOV BX,AX ;Put it in BX
    MOV AX,(0FFFFh/3)+1 ;Maximum time for each sub-delay
    D10: ;Loop to here for each sub-delay
    CMP BX,AX ;Is it more than the maximum?
    JA >D40 ;If so, just do the sub-delay
    MOV AX,BX ;If not, just do the remainder that's left
    D40: ;Do the delay
    CALL DoDelayUS ;Do the US Delay
    SUB BX,AX ;Subtract out how long we just waited
    JNZ D10 ;If not 0 yet, do the sub-delay again
    D90: ;We're done
    POP BX,AX ;Restore used registers
    RET

    DoDelayUS:
    PUSH AX,BX,CX,DX ;Save used registers
    SHL AX,1 ;Multiply by 2
    MOV BX,11932 ;Compensate for the fact
    MUL BX ; that the clock frequency
    MOV BX,10000 ; is actually
    DIV BX ; 1.19318 MHz
    MOV DX,AX ;Save it
    CLI ;Disable interrupts
    CALL GetTimer ;Get the starting timer tick counter
    MOV CX,AX ;Save it
    D20: ;Keep looping to here until we've waited long enough
    MOV BX,CX ;Get the starting timer tick counter
    CALL GetTimer ;Get the current timer tick counter
    SUB BX,AX ;Calculate the elapsed time
    CMP BX,DX ;Has it been long enough?
    JB D20 ;If not, keep waiting
    STI ;Enable interrupts
    D90: ;We're done
    POP DX,CX,BX,AX ;Restore used registers
    RET

    ;------------------------------------------------------------------------------
    ;GET CURRENT TIMER COUNTER FROM PORT 40h (THE CLOCK INTERRUPT)
    ;Inputs:
    ;Outputs: AX = Current timer counter word
    ;Changes:
    ;------------------------------------------------------------------------------
    GetTimer:
    MOV AL,06h ;Bits 7:6 = 00 = Timer 0
    ;Bits 5:4 = 00 = Latch Counter
    ;Bits 3:1 = 011 = Mode 3 (Square Wave)
    ;Bit 0 = 0 = Binary Counter (16 bits)
    OUT 43h,AL ;Tell the PIT what we're going to do
    IN AL,40h ;Get LSB of timer counter
    MOV AH,AL ;Save it
    IN AL,40h ;Get MSB of timer counter
    XCHG AH,AL ;Put things in the right order
    RET

    [/code]
Sign In or Register to comment.