Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Accurate delays in PB/DOS

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Accurate delays in PB/DOS

    Code:
    ' A more accurate, programmable delay (typ. <20usec resoloution) for PB3.5
    ' intended to replace DELAY which has a resoloution of only 50msec.
    ' Because this is meant to be fast, the scaling of the delay value from
    ' usec to internal clock ticks is done outside the delay routine. The
    ' routine is now called with the number of timer ticks needed for the
    ' delay and not the no.of usecs. This is to keep the routine suitable for
    ' use on machines with no FPU where the multiplication by 1.19318 can take
    ' 100's of usec.The scaling can then be done in advance. The multiplication
    ' can easily be moved back into the delay routine if required to give a
    ' delay in microseconds.
    ' The routine uses PIT timer 0 which is also used by the system clock.
    ' When called for the first time the timer is set to the mode required
    ' by the routine, the system clock may therefore lose upto 1 tick (54msec)
    ' when the routine is first called. Subsequent calls only read the counter.
    
    REM test mdelay against MTIMER
    do
    input"Delay for how long(us)";del&&
    del&&=del&& * 1.19318167 :REM convert from usec to timer ticks
    mtimer
    
    mdelay (del&&)
    
    k&=mtimer
    PRINT k&
    loop
    
    
    SUB mdelay(duration&&)
    REM delay for duration&& times 0.838usec(1/1.19318167MHz clk)
    
    !test byte CalledBefore,&hff	;has routine been called before?
    !jnz NoInit		;not zero, so it's been called, don't init
    
    !dec byte CalledBefore	;set CalledBefore flag
    
    !mov al,&h34            ;make sure PIT timer0 is in mode 2
    !out &h43,al
    !mov al,0               ;and set to 0 (i.e a 65536 count)
    !out &h40,al
    !out &h40,al
    
    NoInit:
    !les bx,Int1cV		;get address of Int1c vector
    !mov ax,es:[bx]		;copy offset to ExitVector
    !mov ExitVector[01],ax
    !mov ax,es:[bx+02]	;copy segment to ExitVector
    !mov ExitVector[03],ax
    
    !cli			;disable interrupts while changing interrupt vector
    !lea ax,Int1cEntry      ;get int routine entry to Int1c vector
    !mov es:[bx],ax         ;move offset of my routine to Int1c vector
    !mov es:[bx+02],cs      ;move segment of my routine to Int1c vector
    !sti                    ;Enable interrupts
    
    !call near GetTime   	;Get the time
    !les bx,duration&&      ;add duration to result and get into working store
    !mov ax,result      	;add the current time to the duration in 0.838us clks
    !add ax,es:[bx]
    !mov TimeOut,ax     	;and put the result in TimeOut
    !mov ax,result[02]
    !adc ax,es:[bx+02]
    !mov TimeOut[02],ax
    !mov ax,result[04]	;only need 37 bits to hold usec for a day
    !adc ax,es:[bx+04]      ;so 3 words is enough for 5 years
    !mov TimeOut[04],ax
    
    WaitLonger:
    !call near GetTime   	;read the time again
    !mov ax,result       	;compare with the TimeOut value
    !sub ax,TimeOut
    !mov ax,result[02]
    !sbb ax,TimeOut[02]
    !mov ax,result[04]
    !sbb ax,TimeOut[04]
    !jb WaitLonger       	;it's below that value so loop back again
    
    !cli			;disable interrupts while restoring interrupt vector
    !les bx,Int1cV		;get address of Int1c vector
    !mov ax,ExitVector[01]  ;Restore Int1c vector
    !mov es:[bx],ax		;restore offset
    !mov ax,ExitVector[03]
    !mov es:[bx+02],ax	;restore segment
    !sti                    ;Enable interrupts
    
    EXIT SUB
    
    GetTime:
    !cli             	;stop interrupts while reading timer
    !mov al,&h00     	;latch current counter in timer 0
    !out &h43,al
    !mov ax,DelayTimer	;get s/w part of time
    !mov Result[02],ax
    !mov ax,DelayTimer[02]
    !mov Result[04],ax
    
    !in al,&h40      ;get h/w part of timer
    !xchg al,ah      ;move it out of the way so I can...
    !in al,&h40      ;..get msb of timer
    !xchg al,ah      ;swap bytes to the right order
    !neg ax          ;negate so down counter becomes an up counter
    		 :'and adjust for 1->0 causing interrupt and not 0->ffff
    !mov Result,ax   ;put least significant result in result
    !sti             ;re-enable interrupts
    !retn            ;return
    
    
    REM Int1c is the user exit from BIOS of the 18.2Hz interrupt routine
    Int1cEntry:
    !pushf                       	;save flags
    !inc word DelayTimer         	;increment DelayTimer (a 4 byte counter)
    !jnz Int1cExit
    !inc word DelayTimer[02]
    
    Int1cExit:
    !popf                   	;restore flags
    
    ExitVector:
    !jmp far ExitVector 	;exit via copy of original int1c vector copied into
                            :'this location immediately after the JMP byte
    
    DelayTimer:
    !dd 0                   ;Timer, counts 18.2Hz interrupts from int1c
    
    Result:
    !dd 0                   ;result of reading timer
    !dw 0
    
    TimeOut:
    !dd 0                   ;general workspace and calculated time out value
    !dw 0
    
    Int1cV:
    !dd &h00000070		;Int1c vector
    
    CalledBefore:
    !db 0
    
    END SUB

    ------------------

  • #2
    Hi,

    Can this routine convert to PBdll6 for Windows?

    Thank


    ------------------

    Comment


    • #3
      Unfortunately, Windows will not allow such access to the timer and other hardware so this routine will never work under Windows.

      Paul.

      Comment

      Working...
      X