00001
00018
#include <stdio.h>
00019
#include <stdlib.h>
00020
#include <limits.h>
00021
#include <signal.h>
00022
#include <time.h>
00023
#include <math.h>
00024
#include <errno.h>
00025
#include <sys/wtime.h>
00026
00027
#include "wattcp.h"
00028
#include "ioport.h"
00029
#include "strings.h"
00030
#include "gettod.h"
00031
#include "pcconfig.h"
00032
#include "pcqueue.h"
00033
#include "language.h"
00034
#include "cpumodel.h"
00035
#include "powerpak.h"
00036
#include "wdpmi.h"
00037
#include "x32vm.h"
00038
#include "rs232.h"
00039
#include "misc.h"
00040
#include "timer.h"
00041
00042
#if (DOSX & PHARLAP)
00043
#include <mw/exc.h>
00044
#endif
00045
00046 DWORD start_time = 0;
00047 DWORD start_day = 0;
00049 BOOL
has_8254 = FALSE;
00050 BOOL
has_rdtsc = FALSE;
00051 BOOL
use_rdtsc = FALSE;
00052 BOOL
using_int8 = FALSE;
00053 DWORD clocks_per_usec;
00055 time_t user_tick_base = 0UL;
00056
DWORD user_tick_msec = 0UL;
00057 BOOL user_tick_active = FALSE;
00058
00059
static DWORD date = 0;
00060
static DWORD date_ms = 0;
00061
00062
00063
00064
00065
#if !(DOSX & DJGPP)
00066
#define TIMER_ISR_PERIOD 10UL
00067
#define TIMER_INTR 8
00068
#endif
00069
00070
#if (DOSX == 0) || (DOSX & DOS4GW)
00071
#define HAVE_TIMER_ISR
00072
00073
static W32_IntrHandler old_int_8 = NULL;
00074
00075
#elif (DOSX & (PHARLAP|X32VM))
00076
#define HAVE_TIMER_ISR
00077
00078
static REALPTR old_int_8, int8_cback;
00079
00080
static RMC_BLK rmBlock_int8;
00081
00082
#elif (DOSX & DJGPP)
00083
#define HAVE_TIMER_ISR
00084
00085
static DWORD itimer_resolution = 0UL;
00086
static void (*old_sigalrm)(
int);
00087
static struct itimerval old_itimer;
00088
#endif
00089
00090
#if defined(HAVE_TIMER_ISR) && !(DOSX & DJGPP)
00091
static DWORD tick_timer_8254 = 0UL;
00092
00093
00094
00095
#define TIMER_8254_COUNT ((1193181UL * TIMER_ISR_PERIOD) / 1000UL)
00096
#endif
00097
00098
00103 void init_timers (
void)
00104 {
00105
#if (DOSX)
00106
hires_timer (TRUE);
00108
#if defined(HAVE_UINT64)
00109
if (
use_rdtsc &&
has_rdtsc)
00110 {
00111
clocks_per_usec = (
DWORD) (
get_cpu_speed() / S64_SUFFIX(1000000));
00112
if (
clocks_per_usec == 0UL)
00113 {
00114 outsnl (
"CPU speed is 0?");
00115
use_rdtsc = FALSE;
00116
has_rdtsc = FALSE;
00117 }
00118 }
00119
set_utc_offset();
00120
#endif
00121
#endif
00122
00123
chk_timeout (0UL);
00124 }
00125
00135 void init_userSuppliedTimerTick (
void)
00136 {
00137 SIO_TRACE ((
"init_userSuppliedTimerTick"));
00138 user_tick_active = TRUE;
00139 user_tick_base = time (NULL);
00140
has_8254 = FALSE;
00141 }
00142
00143
00144
00145
00146
#if defined(__HIGHC__)
00147
#pragma off(Call_trace)
00148
#pragma off(Prolog_trace)
00149
#pragma off(Epilog_trace)
00150
#endif
00151
00152
#include "nochkstk.h"
00153
00162 void userTimerTick (
DWORD elapsed_time_msec)
00163 {
00164 user_tick_msec += elapsed_time_msec;
00165 }
00166
00167
#if defined(HAVE_TIMER_ISR)
00168
00171
#if (DOSX & (DJGPP|PHARLAP|X32VM))
00172 static void new_int_8 (
void)
00173 #
else
00174
static INTR_PROTOTYPE
new_int_8 (
void)
00175 #endif
00176 {
00177
#if !(DOSX & DJGPP)
00178
tick_timer_8254 += TIMER_8254_COUNT;
00179
00180
if (tick_timer_8254 >= 0x10000)
00181 {
00182 tick_timer_8254 -= 0x10000;
00183
00184
#if defined(__WATCOMC__)
00185
_chain_intr (old_int_8);
00186
#elif (DOSX & (PHARLAP|X32VM))
00187
_dx_call_real (old_int_8, &rmBlock_int8, 1);
00188
#else
00189
(*old_int_8)();
00190
#endif
00191
}
00192
else
00193 _outportb (0x20, 0x60);
00194
00195
userTimerTick (TIMER_ISR_PERIOD);
00196
00197
#else
00198
userTimerTick (itimer_resolution / 1000UL);
00199
#endif
00200
00201
00202
#if (DOSX & DJGPP)
00203
00204
#endif
00205
}
00206
00207
void exit_timer_isr (
void)
00208 {
00209
if (!
using_int8)
00210
return;
00211
00212
#if (DOSX & DJGPP)
00213
signal (SIGALRM, old_sigalrm);
00214 setitimer (ITIMER_REAL, &old_itimer, NULL);
00215
#else
00216
if (old_int_8)
00217 {
00218 _outportb (0x43, 0x34);
00219 _outportb (0x40, 0);
00220 _outportb (0x40, 0);
00221
00222 PUSHF_CLI();
00223
00224
#if (DOSX & (PHARLAP|X32VM))
00225
_dx_rmiv_set (TIMER_INTR, old_int_8);
00226
if (int8_cback)
00227 _dx_free_rmode_wrapper (int8_cback);
00228 old_int_8 = 0;
00229 int8_cback = 0;
00230
#else
00231
_dos_setvect (TIMER_INTR, old_int_8);
00232 old_int_8 = NULL;
00233
#endif
00234
00235 POPF();
00236 }
00237
#endif
00238
00239
00240
00241
00242 user_tick_active = FALSE;
00243
using_int8 = FALSE;
00244 }
00245
00246
00247
00248
00249
00250
void init_timer_isr (
void)
00251 {
00252
00253
00254
if (
using_int8)
00255
return;
00256
00257
#if (DOSX & DJGPP)
00258
{
00259
struct itimerval tim;
00260
00261 memset (&tim, 0,
sizeof(tim));
00262 tim.it_interval.tv_usec = 1;
00263 setitimer (ITIMER_REAL, &tim, NULL);
00264 setitimer (ITIMER_REAL, NULL, &tim);
00265 itimer_resolution = 1000000UL * tim.it_interval.tv_sec +
00266 tim.it_interval.tv_usec;
00267 tim.it_value.tv_sec = tim.it_interval.tv_sec;
00268 tim.it_value.tv_usec = tim.it_interval.tv_usec;
00269
00270 memset (&old_itimer, 0,
sizeof(old_itimer));
00271 old_sigalrm = signal (SIGALRM, (W32_IntrHandler)new_int_8);
00272 setitimer (ITIMER_REAL, &tim, &old_itimer);
00273 }
00274
00275
#elif (DOSX & (PHARLAP|X32VM))
00276
#if 1
00277
int8_cback = _dx_alloc_rmode_wrapper_iret ((pmodeHook)new_int_8, 256);
00278
if (!int8_cback)
00279 {
00280 outsnl (_LANG(
"Cannot allocate real-mode timer callback"));
00281
return;
00282 }
00283 _dx_rmiv_get (8, &old_int_8);
00284 _dx_rmiv_set (8, int8_cback);
00285
#else
00286
{
00287 FARPTR fp;
00288 FP_SET (fp, new_int_8, MY_CS());
00289 _dx_pmiv_get (8, &old_int_8_pm);
00290 _dx_apmiv_set (8, fp);
00291 }
00292
#endif
00293
#else
00294
old_int_8 = _dos_getvect (8);
00295 _dos_setvect (8, new_int_8);
00296
#endif
00297
00298
#if !(DOSX & DJGPP)
00299
_outportb (0x43, 0x34);
00300 _outportb (0x40, loBYTE(TIMER_8254_COUNT));
00301 _outportb (0x40, hiBYTE(TIMER_8254_COUNT));
00302
#endif
00303
00304
init_userSuppliedTimerTick();
00305
using_int8 = TRUE;
00306
00307
00308 RUNDOWN_ADD (exit_timer_isr, -2);
00309 }
00310
00311
#else
00312
00313
void init_timer_isr (
void)
00314 {
00315
#if defined(USE_DEBUG)
00316
if (debug_on)
00317 outsnl (
"No timer-ISR in this environment");
00318
#endif
00319
}
00320
00321
void exit_timer_isr (
void)
00322 {
00323 }
00324
#endif
00325
00335 int cmp_timers (
DWORD t1,
DWORD t2)
00336 {
00337
if (t1 == t2)
00338
return (0);
00339
return (t1 < t2 ? -1 : +1);
00340 }
00341
00351 int hires_timer (
int on)
00352 {
00353
int old =
has_8254;
00354
00355 SIO_TRACE ((
"hires_timer %s", on ?
"on" :
"off"));
00356
has_8254 = on;
00357
chk_timeout (0UL);
00358
return (old);
00359 }
00360
00361
00362
#if !defined(WIN32)
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
DWORD clockbits (
void)
00387 {
00388
static VOLATILE
DWORD count;
00389
00390
#if 1
00391
00392
00393
00394
00395
static BOOL started = FALSE;
00396
00397 PUSHF_CLI();
00398
00399
if (!started)
00400 {
00401 _outportb (0x43, 0x34);
00402 _outportb (0x40, 0x00);
00403 _outportb (0x40, 0x00);
00404 started = TRUE;
00405 }
00406
00407 _outportb (0x43, 0x04);
00408 count = _inportb (0x40);
00409 count |= _inportb (0x40) << 8;
00410
00411 POPF();
00412
00413
return (count);
00414
00415
#else
00416
static VOLATILE
DWORD stat, count;
00417
00418
do
00419 {
00420 PUSHF_CLI();
00421 _outportb (0x43, 0xC2);
00422 stat = _inportb (0x40);
00423 count = _inportb (0x40);
00424 count |= _inportb (0x40) << 8;
00425 POPF();
00426 }
00427
while (stat & 0x40);
00428
00429 stat = (stat & 0x80) << 8;
00430 count >>= 1;
00431
if (count == 0)
00432
return (stat ^ 0x8000UL);
00433
return (count | stat);
00434
#endif
00435
}
00436
00437
#if !defined(W32_NO_8087)
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
DWORD millisec_clock (
void)
00452 {
00453
DWORD hi;
00454
WORD lo;
00455
double x;
00456
00457
do
00458 {
00459 hi = PEEKL (0, BIOS_CLK);
00460 lo = clockbits();
00461 }
00462
while (hi != PEEKL(0, BIOS_CLK));
00463 lo = 0 - lo;
00464
00465
00466
00467 x = ldexp ((
double)hi, 16) + (
double)lo;
00468
return (
DWORD) (x * 4.0 / 4770.0);
00469 }
00470
#endif
00471
#endif
00472
00473
00478 DWORD set_timeout (
DWORD msec)
00479 {
00480
DWORD ret;
00481
00482
if (user_tick_active)
00483 {
00484 ret = user_tick_msec + msec;
00485 }
00486
#if defined(HAVE_UINT64) || \
00487 defined(WIN32)
00488
else
00489 {
00490
struct timeval now;
00491
00492 gettimeofday2 (&now, NULL);
00493 ret = msec + 1000 * (
DWORD)now.tv_sec + (
DWORD)(now.tv_usec / 1000);
00494 }
00495
#else
00496
00497
#if !defined(W32_NO_8087)
00498
else if (
has_8254)
00499 {
00500 ret = msec + date_ms + millisec_clock();
00501 }
00502
#endif
00503
else
00504 {
00505
DWORD ticks = 1;
00506
00507
if (msec > 55)
00508 ticks = msec / 55UL;
00509
00510 ret = ticks + date + PEEKL (0,BIOS_CLK);
00511 }
00512
#endif
00513
00514
return (ret == 0 ? 1 : ret);
00515 }
00516
00522 BOOL
chk_timeout (
DWORD value)
00523 {
00524
if (user_tick_active)
00525 {
00526
if (value == 0)
00527
return (0);
00528
return (user_tick_msec >= value);
00529 }
00530
00531
#if defined(HAVE_UINT64) || defined(WIN32)
00532
if (value == 0UL)
00533
return (0);
00534
return (
set_timeout(0) >= value);
00535
00536
#else
00537
{
00538
static char oldHour = -1;
00539
#if !defined(W32_NO_8087)
00540
static DWORD now_ms;
00541
#endif
00542
static DWORD now;
00543
char hour;
00544
00545 now = (
DWORD) PEEKL (0, BIOS_CLK);
00546
#if 1
00547
hour = (
char)(now >> 16U);
00548
#else
00549
hour = (
char)(now/65543.33496093);
00550
#endif
00551
00552
if (hour != oldHour)
00553 {
00554
if (hour < oldHour)
00555 {
00556
#define CORR 290UL
00557 date += 1572750UL + CORR;
00558 date_ms += 3600UL*24UL*1000UL;
00559 }
00560 oldHour = hour;
00561 }
00562
00563
if (value == 0L)
00564
return (0);
00565
00566
#if !defined(W32_NO_8087)
00567
if (
has_8254)
00568 {
00569 now_ms = millisec_clock();
00570
return (now_ms + date_ms >= value);
00571 }
00572
#endif
00573
now += date;
00574
return (now >= value);
00575 }
00576
#endif
00577 }
00578
00583 int set_timediff (
long msec)
00584 {
00585 date_ms -= msec;
00586 date -= msec/55;
00587
return (0);
00588 }
00589
00596 long get_timediff (
DWORD now,
DWORD tim)
00597 {
00598
#if defined(HAVE_UINT64) || defined(WIN32)
00599
return (
long)(now - tim);
00600
#else
00601
long dt = (
long)(now - tim);
00602
00603
if (
has_8254)
00604 dt = dt % (3600L*24L*1000L);
00605
else dt = dt % (1572750L + CORR);
00606
return (dt);
00607
#endif
00608
}
00609
00610
#if !defined(W32_NO_8087)
00611
00612
00613
00614
double timeval_diff (
const struct timeval *newer,
const struct timeval *older)
00615 {
00616
long d_sec = (
long)newer->tv_sec - (
long)older->tv_sec;
00617
long d_usec = newer->tv_usec - older->tv_usec;
00618
return ((1E6 * (
double)d_sec) + (
double)d_usec);
00619 }
00620
#endif
00621
00622
#if defined(WIN32)
00623
00624
00625
00626
double filetime_sec (
const void *filetime)
00627 {
00628
const LARGE_INTEGER ft = *(
const LARGE_INTEGER*) filetime;
00629
long double rc = (
long double)ft.QuadPart;
00630
00631
return (
double) (rc/1E7);
00632 }
00633
#endif
00634
00635
#if defined(USE_DEBUG)
00636
00637
00638
00639
00640
00641
const char *time_str (
DWORD val)
00642 {
00643
static char buf[30];
00644
char fmt[6];
00645
double flt_val;
00646
00647
if (
has_8254 ||
has_rdtsc || user_tick_active)
00648 {
00649 flt_val = (
double)val / 1000.0F;
00650 strcpy (fmt,
"%.3f");
00651 }
00652
else
00653 {
00654 flt_val = (
double)val / 18.2F;
00655 strcpy (fmt,
"%.2f");
00656 }
00657
00658
#if (!DOSX) && defined(__BORLANDC__) && 0
00659 fmt[3] =
'l';
00660 fmt[4] =
'f';
00661 fmt[5] =
'\0';
00662
#endif
00663
00664 sprintf (buf, fmt, flt_val);
00665
return (buf);
00666 }
00667
00668
00669
00670
00671
const char *hms_str (
DWORD sec)
00672 {
00673
static char buf[30];
00674
WORD hour = (
WORD) (sec / 3600UL);
00675
WORD min = (
WORD) (sec / 60) - (60 * hour);
00676
00677 sprintf (buf,
"%02u:%02u:%02u", hour, min, (
UINT)(sec % 60UL));
00678
return (buf);
00679 }
00680
00681
00682
00683
00684
00685
const char *elapsed_str (
DWORD val)
00686 {
00687
static char buf[30];
00688
WORD hour, min, msec;
00689
DWORD sec;
00690 BOOL is_win = (DOSX & WINWATT);
00691
00692
if (val == 0UL)
00693
return (
"00:00:00.000");
00694
00695
if (!user_tick_active && val <
start_time)
00696 val = ULONG_MAX - val +
start_time;
00697
00698
00699
00700
00701
if (user_tick_active)
00702 {
00703 sec = val / 1000UL;
00704 msec = (
WORD) (val % 1000UL);
00705 }
00706
else if (
has_8254 ||
has_rdtsc || is_win)
00707 {
00708 val -=
start_time;
00709 sec = val / 1000UL;
00710 msec = (
WORD) (val % 1000UL);
00711 }
00712
else
00713 {
00714 val -=
start_time;
00715 sec = val / 18;
00716 msec = 55 * (
WORD)(val % 18UL);
00717 }
00718
00719 hour = (
WORD) (sec / 3600UL);
00720 min = (
WORD) (sec / 60UL) - 60 * hour;
00721 sec = sec % 60UL;
00722 sprintf (buf,
"%02u:%02u:%02lu.%03u", hour, min, sec, msec);
00723
return (buf);
00724 }
00725
#endif
00726
00727
00728
#if !defined(WIN32)
00729
00730
00731
00732
00733
#define TICKS_DAY 1573067UL
00734
00735
DWORD ms_clock (
void)
00736 {
00737
static DWORD lastTick, tickOffset;
00738
static char firstTime = 1;
00739
DWORD tick = PEEKL (0, 0x46C);
00740
00741
if (firstTime)
00742 {
00743 firstTime = 0;
00744 lastTick = tickOffset = tick;
00745
return (0);
00746 }
00747
if (lastTick > tick)
00748 tickOffset -= TICKS_DAY;
00749 lastTick = tick;
00750
return (tick - tickOffset);
00751 }
00752
#endif
00753
00754
00755
00756
#if (DOSX) && defined(HAVE_UINT64)
00757
00758
00759
00760
static void Wait_N_ticks (
int num)
00761 {
00762
DWORD tim;
00763
00764
while (num--)
00765 {
00766
#if defined(WIN32)
00767
tim = GetTickCount() + 55;
00768
while (GetTickCount() < tim)
00769 Sleep (0);
00770
#else
00771
tim = PEEKL (0, BIOS_CLK);
00772
while (PEEKL(0,BIOS_CLK) == tim)
00773 {
00774
#ifdef __DJGPP__
00775
ENABLE();
00776
#else
00777
((
void)0);
00778
#endif
00779
}
00780
#endif
00781
}
00782 }
00783
00787 uint64 get_cpu_speed (
void)
00788 {
00789
#define NUM_SAMPLES 3
00790
#define WAIT_TICKS 2
00791
00792
uint64 speed;
00793
uint64 sample [NUM_SAMPLES];
00794
int i;
00795
00796 Wait_N_ticks (1);
00797
00798
for (i = 0; i < NUM_SAMPLES; i++)
00799 {
00800
uint64 start = GET_RDTSC();
00801
00802 Wait_N_ticks (WAIT_TICKS);
00803 sample[i] = 1000 * (GET_RDTSC() - start) / (WAIT_TICKS*55);
00804 }
00805
00806 speed = 0;
00807
for (i = 0; i < NUM_SAMPLES; i++)
00808 speed += sample[i];
00809
return (speed / NUM_SAMPLES);
00810 }
00811
#endif
00812