Mail Archives: djgpp-workers/2002/12/08/03:08:19
> > This was discussed a while ago and I cannot remember if there was a
solution
> > proposed, except one I worked on. Below is a modified delay.c that
works on
> > XP. It does have some problems in that it is only accuate to approx 27
> > milliseconds as the TOD tick is updated every 54.9 millisends and I do a
> > manual rounding check in the code in order to try to make the delay a
bit
> > more accurate.
>
> I also worked on something similar - my WIP from last year is attached at
> the bottom. I was trying to get more accuracy, but due to the unsync
> between the counter and tick rollover, I think there were bugs I hadn't
> fixed in the stuff below (it didn't work?). I also tried to call the
> int15 call and checked for success, just in case they fixed it some day.
>
> Yours looks fine, and I think we ought to get it into the library for the
next
> release. Maybe document the accuracy issue. Maybe do some yields in the
busy
> loop. Thanks for working on this, I'm just completely swamped.
Charles,
I modified the code to try the int 15 and if it failed then use the TOD tick
time as you indicated if MS fix it down the tack. I added the yields,
hopefully in the right spots and modified the txh file. I do not know what
to put in the docs so any help is appreciated even if it is I don't
understand it.
Below are the patches, one for delay.c and the other for delay.txh.
Any more comments on the delay.c mods?
*** \djgppcvs\src\libc\dos\dos\delay.c Tue Mar 21 18:35:38 1995
--- .\src\libc\dos\dos\delay.c Sun Dec 8 18:59:16 2002
***************
*** 1,10 ****
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <dos.h>
#include <dpmi.h>
! void delay(unsigned msec)
{
__dpmi_regs r;
while (msec)
{
unsigned usec;
--- 1,54 ----
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+
#include <dos.h>
#include <dpmi.h>
! /*--------------------------------------------------
! INT 15 - BIOS - WAIT (AT,PS)
! AH = 86h
! CX:DX = interval in microseconds
! Return: CF clear if successful (wait interval elapsed)
! CF set on error or AH=83h wait already in progress
! AH = status (see #00496)
! Note: the resolution of the wait period is 977 microseconds on many
systems
! because many BIOSes use the 1/1024 second fast interrupt from the AT
! real-time clock chip which is available on INT 70; because newer
! BIOSes may have much more precise timers available, it is not
! possible to use this function accurately for very short delays unless
! the precise behavior of the BIOS is known (or found through testing)
! SeeAlso: AH=41h,AH=83h,INT 1A/AX=FF01h,INT 70
! Note: Does not work on Win 2K or XP!!!!
! --------------------------------------------------
! INT 1A - TIME - GET SYSTEM TIME
! AH = 00h
! Return: CX:DX = number of clock ticks since midnight
! AL = midnight flag, nonzero if midnight passed since time last read
! Notes: there are approximately 18.2 clock ticks per second, 1800B0h per 24
! hrs
! (except on Tandy 2000, where the clock runs at 20 ticks per second)
! IBM and many clone BIOSes set the flag for AL rather than incrementing
! it, leading to loss of a day if two consecutive midnights pass
! without a request for the time (e.g. if the system is on but idle)
! since the midnight flag is cleared, if an application calls this
! function after midnight before DOS does, DOS will not receive the
! midnight flag and will fail to advance the date
! Modern releases of MS-DOS/PC DOS (5.0+???) assume that AL is a day
! rollover counter rather than a flag, as expected by older releases.
! DOS 5 - 7.10 (Windows 98 SE) provide an undocumented CONFIG.SYS
! SWITCHES=/T option to force the old behaviour of the day advancing
! code, that is using a flag instead of a counter.
! DR DOS 3.31 - DR-DOS 7.03 handle AL as a flag.
! SeeAlso: AH=01h,AH=02h,INT 21/AH=2Ch,INT 55"Tandy 2000",INT 4E/AH=02h"TI"
! SeeAlso: INT 62/AX=0099h,MEM 0040h:006Ch,MEM 0040h:0070h
! --------------------------------------------------*/
!
! #define tick_per_day (24*60*60*10000/182)
!
! void ac_delay(unsigned msec)
{
__dpmi_regs r;
+
while (msec)
{
unsigned usec;
***************
*** 16,21 ****
--- 60,104 ----
r.x.cx = usec>>16;
r.x.dx = usec & 0xffff;
__dpmi_int(0x15, &r);
+ if ((r.x.flags & 1) || (r.h.ah == 0x83))
+ {
+ /* INT 15 FAILED, so fall back to the Time Of Day Tick */
+ unsigned long start_tick;
+ unsigned long end_tick;
+
+ r.h.ah = 0x00;
+ __dpmi_int(0x1A, &r);
+
+ start_tick = (r.x.cx << 16) + (r.x.dx & 0xffff);
+ end_tick = (msec*182)/10000 + start_tick;
+
+ if ((msec%10000/182) > (5000/182)) /* Manual round ticks */
+ {
+ end_tick++;
+ }
+ if (end_tick > tick_per_day) /* Tick time past midnight */
+ {
+ /* check for midnight */
+ while (r.h.al == 0)
+ {
+ r.h.ah = 0x00;
+ __dpmi_int(0x1A, &r);
+ __dpmi_yield();
+ }
+ end_tick = end_tick - tick_per_day;
+ }
+
+ while (((r.x.cx << 16) + (r.x.dx & 0xffff)) <= end_tick)
+ {
+ r.h.ah = 0x00;
+ __dpmi_int(0x1A, &r);
+ __dpmi_yield();
+ }
+ msec = 0; /* waited the required time */
+ }
+ else
+ {
msec -= msec_this;
}
}
+ }
*** \djgppcvs\src\libc\dos\dos\delay.txh Mon Sep 6 22:39:32 1999
--- .\src\libc\dos\dos\delay.txh Sun Dec 8 18:54:14 2002
***************
*** 13,22 ****
It uses the @code{int 15h} delay function to relinquish the CPU to other
programs that might need it.
! Some operating systems that emulate DOS, such as OS/2 and Windows/NT,
! hang the DOS session when the @key{Pause} key is pressed during the call
! to @code{delay}. Plain DOS and Windows 3.X and 9X are known to not have
! this bug.
@subheading Return Value
--- 13,26 ----
It uses the @code{int 15h} delay function to relinquish the CPU to other
programs that might need it.
! Some operating systems that emulate DOS, such as OS/2, Windows/NT, Windows
2000
! and Windows XP hang the DOS session when the @key{Pause} key is pressed
during
! the call to @code{delay}. Plain DOS and Windows 3.X and 9X are known to
! not have this bug. On Windows 2000 and XP to exit the pause press any key.
!
! Windows 2000 and XP delay resolution is 54.9 millisecond. Under Windows
! 2000 and XP the delay function uses the Time Of Day Tick which occurs
! 18.2 times per second.
@subheading Return Value
- Raw text -