/shark/trunk/oslib/kl/time.c |
---|
21,6 → 21,13 |
/* Time management code: ll_getttime() */ |
/* Added Advanced Timer Code |
* |
* Date: 8.4.2003 |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
* |
*/ |
#include <ll/i386/pit.h> |
#include <ll/i386/stdlib.h> |
#include <ll/i386/error.h> |
41,6 → 48,8 |
extern BYTE frc; |
extern int activeEvent; |
extern unsigned char use_tsc; |
FILE(Time); |
TIME ll_gettime(int mode, struct timespec *tsres) |
49,6 → 58,8 |
BYTE isr; |
struct timespec tmp; |
if (!use_tsc) { |
#if 1 |
if (activeEvent) { |
if (tsres != NULL) { |
125,4 → 136,69 |
} |
} |
return 0; |
} else { |
#if 1 |
if (activeEvent) { |
if (tsres != NULL) { |
read_timespec(tsres); |
} else { |
struct timespec tmp; |
read_timespec(&tmp); |
return TIMESPEC2USEC(&tmp); |
} |
return TIMESPEC2USEC(tsres); |
} |
#endif |
if (mode == TIME_PTICK) { |
if (timermode != LL_PERIODIC) { |
return 0; |
} |
if(tsres != NULL) { |
read_timespec(tsres); |
} else { |
struct timespec tmp; |
read_timespec(&tmp); |
return TIMESPEC2USEC(&tmp); |
} |
return TIMESPEC2USEC(tsres); |
} |
if (mode == TIME_NEW) { |
if (tsres != NULL) { |
read_timespec(tsres); |
return TIMESPEC2USEC(tsres); |
} else { |
struct timespec tmp; |
read_timespec(&tmp); |
return TIMESPEC2USEC(&tmp); |
} |
} |
if (mode == TIME_EXACT) { |
if (timermode == LL_PERIODIC) { |
if (tsres != NULL) { |
read_timespec(tsres); |
} else { |
struct timespec tmp; |
read_timespec(&tmp); |
return TIMESPEC2USEC(&tmp); |
} |
return TIMESPEC2USEC(tsres); |
} else { |
return 0; |
} |
} |
return 0; |
} |
} |
/shark/trunk/oslib/kl/event.c |
---|
19,6 → 19,13 |
* For legalese, check out the included GPL license. |
*/ |
/* Added Advanced Timer Code |
* |
* Date: 8.4.2003 |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
* |
*/ |
/* Time Event routines */ |
#include <ll/i386/stdlib.h> |
61,6 → 68,8 |
extern void (*evt_prol) (void); |
extern void (*evt_epil) (void); |
extern unsigned char use_tsc; |
void event_setlasthandler(void *p) |
{ |
last_handler = p; |
152,17 → 161,23 |
struct event *p, *pp; |
WORD tmp; |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
if(!use_tsc) { |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
} |
activeInt++; |
if (activeInt == 1 && evt_prol != NULL) { |
evt_prol(); |
} |
ADDNANO2TIMESPEC(nts, &actTime); |
if (!use_tsc) { |
ADDNANO2TIMESPEC(nts, &actTime); |
} else { |
read_timespec(&actTime); |
} |
for (p = firstevent; p != NULL; p = pp) { |
/* |
SUBTIMESPEC(&(p->time), &actTime, &tmp); |
197,7 → 212,7 |
IDT_place(0x40,ll_timer); |
if (l->mode != LL_PERIODIC) { |
error("Trying one-shot!!!"); |
message("One-shot mode\n"); |
t = 0; |
/* Mode: Binary/Mode 4/16 bit Time_const/Counter 0 */ |
pit_init(0, TMR_MD4, 0xFFFF); /* Timer 0, Mode 4, constant 0xFFFF */ |
256,6 → 271,8 |
/* Initialization of the time variables for periodic mode */ |
nts = ticksize * 1000; |
NULL_TIMESPEC(&actTime); |
if (use_tsc) ll_init_advtimer(); |
/* Initialization of the general time variables */ |
NULLPITSPEC(&globalCounter); |
/shark/trunk/oslib/kl/event1.c |
---|
19,6 → 19,13 |
* For legalese, check out the included GPL license. |
*/ |
/* Added Advanced Timer Code |
* |
* Date: 8.4.2003 |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
* |
*/ |
/* Time Event routines (one shot mode) */ |
#include <ll/i386/stdlib.h> |
45,6 → 52,8 |
extern void (*evt_prol) (void); |
extern void (*evt_epil) (void); |
extern unsigned char use_tsc; |
/* TODO: oneshot_event_delete & oneshot_event_init... */ |
/* Switched to timespec */ |
112,12 → 121,20 |
WORD tmp; |
DWORD tnext; |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
if (!use_tsc) { |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
PITSPEC2TIMESPEC(&globalCounter, &now); |
PITSPEC2TIMESPEC(&globalCounter, &now); |
} else { |
read_timespec(&now); |
} |
if (firstevent != NULL) { |
activeEvent = 1; |
if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) { |
144,13 → 161,22 |
} |
activeInt--; |
} |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
PITSPEC2TIMESPEC(&globalCounter, &now); |
if (!use_tsc) { |
tmp = pit_read(frc); |
ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter); |
lastTime = tmp; |
PITSPEC2TIMESPEC(&globalCounter, &now); |
} else { |
read_timespec(&now); |
} |
if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) { |
NULL_TIMESPEC(&ttmp); |
} else { |
/shark/trunk/oslib/kl/init.c |
---|
183,7 → 183,8 |
void abort_tail(int code) |
{ |
message("ABORT %d !!!",code); |
l1_end(); |
restore_CMOS(); |
l1_end(); |
sti(); |
l1_exit(1); |
} |
190,6 → 191,7 |
void ll_end(void) |
{ |
restore_CMOS(); |
l1_end(); |
} |
/shark/trunk/oslib/kl/advtimer.c |
---|
0,0 → 1,267 |
/* Project: OSLib |
* Description: The OS Construction Kit |
* Date: 1.6.2000 |
* Idea by: Luca Abeni & Gerardo Lamastra |
* |
* OSLib is an SO project aimed at developing a common, easy-to-use |
* low-level infrastructure for developing OS kernels and Embedded |
* Applications; it partially derives from the HARTIK project but it |
* currently is independently developed. |
* |
* OSLib is distributed under GPL License, and some of its code has |
* been derived from the Linux kernel source; also some important |
* ideas come from studying the DJGPP go32 extender. |
* |
* We acknowledge the Linux Community, Free Software Foundation, |
* D.J. Delorie and all the other developers who believe in the |
* freedom of software and ideas. |
* |
* For legalese, check out the included GPL license. |
*/ |
/* Advanced Timer Managment |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
*/ |
#include <ll/i386/stdlib.h> |
#include <ll/i386/error.h> |
#include <ll/i386/advtimer.h> |
#include <ll/sys/ll/ll-data.h> |
#include <ll/sys/ll/ll-func.h> |
#include <ll/i386/pic.h> |
#include <ll/sys/ll/event.h> |
#include <ll/sys/ll/time.h> |
unsigned char use_tsc = 0; //Enable the TSC counter mode |
unsigned char use_cmos = 0; //Enable the RTC correction |
//Max single delta_clk_per_msec increment |
#define MAX_DELTA_INK 10 |
//Max delta_clk_per_msec before declare lost |
//the CMOS sync |
#define MAX_DELTA_TOT 100 |
signed long long init_tsc; |
signed long long init_nsec; //Warp around 292 years !! |
signed long long clk_per_msec; |
signed long last_delta_clk_per_msec; |
signed long total_delta_clk_per_msec; |
unsigned char save_CMOS_regA; |
unsigned char save_CMOS_regB; |
void HandlerIRQ8(void *p) |
{ |
unsigned char set; |
static unsigned long init_step = 0; |
signed long long actual_tsc; |
signed long long dt,dn; |
signed long delta_clk_per_msec; |
cli(); |
CMOS_READ(0x0C,set); |
rdtscll(actual_tsc); |
//Delta TSC |
dt = actual_tsc - init_tsc; |
init_tsc = actual_tsc; |
UNSIGNED_TSC2NSEC(dt,&dn); |
//Offset |
init_nsec += dn; |
if (init_step < 5) { |
init_step++; |
return; |
} |
dn = dn % 1000000000 - 500000000; |
//Delta clk/msec |
delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn); |
//clk_per_msec adjustment |
if (delta_clk_per_msec < 0) { |
if (delta_clk_per_msec > -MAX_DELTA_INK) |
clk_per_msec += delta_clk_per_msec; |
else |
clk_per_msec -= MAX_DELTA_INK; |
} else { |
if (delta_clk_per_msec < MAX_DELTA_INK) |
clk_per_msec += delta_clk_per_msec; |
else |
clk_per_msec += MAX_DELTA_INK; |
} |
if (delta_clk_per_msec > MAX_DELTA_TOT || delta_clk_per_msec < -MAX_DELTA_TOT) { |
message("Error: Delta_clk_per_msec |%ld| > %ld\n",\ |
(long)delta_clk_per_msec,(long)MAX_DELTA_TOT); |
ll_abort(10); |
} |
last_delta_clk_per_msec = delta_clk_per_msec; |
total_delta_clk_per_msec += delta_clk_per_msec; |
sti(); |
} |
#define HZ 100 |
#ifdef CONFIG_MELAN |
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ |
#else |
# define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ |
#endif |
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) |
#define CALIBRATE_LATCH (5 * LATCH) |
#define CALIBRATE_TIME (5 * 1000020/HZ) |
//TSC Calibration (idea from the linux kernel code) |
void ll_calibrate_tsc(void) |
{ |
signed long long start; |
signed long long end; |
signed long long dtsc; |
signed long start_8253, end_8253, delta_8253; |
cli(); |
/* Set the Gate high, disable speaker */ |
outp(0x61, (inp(0x61) & ~0x02) | 0x01); |
outp(0x43,0xB0); /* binary, mode 0, LSB/MSB, Ch 2 */ |
outp(0x42,CALIBRATE_LATCH & 0xff); /* LSB of count */ |
outp(0x42,CALIBRATE_LATCH >> 8); /* MSB of count */ |
rdtscll(start); |
outp(0x43,0x00); |
start_8253 = inp(0x42); |
start_8253 |= inp(0x42) << 8; |
do { |
outp(0x43,0x00); |
end_8253 = inp(0x42); |
end_8253 |= inp(0x42) << 8; |
} while (end_8253 > 10); |
rdtscll(end); |
outp(0x43,0x00); |
end_8253 = inp(0x42); |
end_8253 |= inp(0x42) << 8; |
//Delta TSC |
dtsc = end - start; |
//Delta PIT |
delta_8253 = start_8253 - end_8253 + 1; |
if (delta_8253 > 0xFFFF) { |
message("Error calculating Delta PIT\n"); |
ll_abort(10); |
} |
message("Delta TSC = %10ld\n",(long)dtsc); |
message("Delta PIT = %10ld\n",(long)delta_8253); |
clk_per_msec = dtsc * CALIBRATE_LATCH * 1000 / delta_8253 / CALIBRATE_TIME; |
message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec); |
sti(); |
} |
//Low level time read function |
void read_timespec(struct timespec *tspec) |
{ |
signed long long actual_tsc; |
signed long long dt,dn; |
rdtscll(actual_tsc); |
tspec->tsc = actual_tsc; |
dt = actual_tsc - init_tsc; |
UNSIGNED_TSC2NSEC(dt,&dn); |
tspec->tv_sec = (init_nsec + dn) / 1000000000; |
tspec->tv_nsec = (init_nsec + dn) % 1000000000; |
} |
void ll_init_advtimer() |
{ |
if (use_tsc) { |
ll_calibrate_tsc(); |
last_delta_clk_per_msec = 0; |
total_delta_clk_per_msec = 0; |
rdtscll(init_tsc); // Read start TSC |
init_nsec = 0; |
if (use_cmos) { |
message("CMOS adjustment enabled\n"); |
cli(); |
irq_bind(8, HandlerIRQ8, INT_FORCE); |
CMOS_READ(0x0A,save_CMOS_regA); |
CMOS_READ(0x0B,save_CMOS_regB); |
CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt |
CMOS_WRITE(0x0B,0x42); // Enable Interrupt |
irq_unmask(8); |
sti(); |
} |
} else { |
use_cmos = 0; |
} |
} |
void restore_CMOS() |
{ |
if (use_cmos) { |
cli(); |
irq_mask(8); |
CMOS_WRITE(0x0A,save_CMOS_regA); |
CMOS_WRITE(0x0B,save_CMOS_regB); |
sti(); |
} |
} |
/shark/trunk/oslib/kl/makefile |
---|
24,7 → 24,8 |
aspace.o \ |
intevt.o \ |
event.o \ |
event1.o |
event1.o \ |
advtimer.o |
KL_OBJ = $(KL_C_OBJ) abort.o timeint.o |
/shark/trunk/oslib/ll/i386/advtimer.h |
---|
0,0 → 1,61 |
/* Project: OSLib |
* Description: The OS Construction Kit |
* Date: 1.6.2000 |
* Idea by: Luca Abeni & Gerardo Lamastra |
* |
* OSLib is an SO project aimed at developing a common, easy-to-use |
* low-level infrastructure for developing OS kernels and Embedded |
* Applications; it partially derives from the HARTIK project but it |
* currently is independently developed. |
* |
* OSLib is distributed under GPL License, and some of its code has |
* been derived from the Linux kernel source; also some important |
* ideas come from studying the DJGPP go32 extender. |
* |
* We acknowledge the Linux Community, Free Software Foundation, |
* D.J. Delorie and all the other developers who believe in the |
* freedom of software and ideas. |
* |
* For legalese, check out the included GPL license. |
*/ |
/* Advanced Timer |
* Date: 8.4.2003 |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
* |
*/ |
#ifndef __ADVTIMER_H__ |
#define __ADVTIMER_H__ |
#include <ll/i386/defs.h> |
BEGIN_DEF |
/* TSC */ |
#define rdtsc(low,high) \ |
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) |
#define rdtscll(val) \ |
__asm__ __volatile__("rdtsc" : "=A" (val)) |
/* RTC */ |
#define RTC_PORT(x) (0x70 + (x)) |
#define CMOS_READ(addr,val) \ |
{ \ |
outp(RTC_PORT(0),(addr)); \ |
val = inp(RTC_PORT(1)); \ |
} |
#define CMOS_WRITE(addr,val) \ |
{ \ |
outp(RTC_PORT(0),(addr)); \ |
outp(RTC_PORT(1),(val)); \ |
} |
#define RTC_IRQ 8 |
END_DEF |
#endif |
/shark/trunk/oslib/ll/sys/ll/time.h |
---|
19,6 → 19,13 |
* For legalese, check out the included GPL license. |
*/ |
/* Added Advanced Timer Code |
* |
* Date: 8.4.2003 |
* Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
* |
*/ |
/* Inline functions for managing timespec structures. |
All timespec values are pointers!!! |
This file defines these functions: |
49,6 → 56,10 |
TIMESPEC_ASSIGN(t1,t2) |
t1 = t2 */ |
/* Advanced Timer Support |
* Giacomo Guidi <giacomo@gandalf.sssup.it> |
*/ |
#ifndef __LL_SYS_LL_TIME_H__ |
#define __LL_SYS_LL_TIME_H__ |
55,11 → 66,66 |
#include <ll/i386/defs.h> |
BEGIN_DEF |
extern signed long long clk_per_msec; |
extern signed long long init_tsc; |
extern unsigned char use_tsc; |
struct timespec { |
long tv_sec; /* Seconds */ |
long tv_nsec; /* Nanoseconds */ |
long tv_sec; /* Seconds */ |
long tv_nsec; /* Nanoseconds */ |
long long tsc; /* 64 bit TSC */ |
}; |
extern __inline__ void UNSIGNED_TSC2NSEC(unsigned long long tsc, unsigned long long *n) |
{ |
unsigned long nl,nh; |
nl = *n & 0xFFFFFFFF; |
nh = *n >> 32; |
__asm__("mull %%ecx\n\t" |
"movl %%eax,%%esi\n\t" |
"movl %%edx,%%edi\n\t" |
"xorl %%edx,%%edx\n\t" |
"movl %6,%%eax\n\t" |
"mull %%ecx\n\t" |
"addl %%edi,%%eax\n\t" |
"adcl $0,%%edx\n\t" |
"movl %5,%%ecx\n\t" |
"divl %%ecx\n\t" |
"xchgl %%eax,%%esi\n\t" |
"divl %%ecx\n\t" |
: "=a" (nl), "=S" (nh) |
: "c" (1000000), "a" ((unsigned long)(tsc & 0xFFFFFFFF)), "d" (0), |
"m" ((unsigned long)(clk_per_msec)), "m" ((unsigned long)(tsc >> 32)), |
"S" (0), "D" (0)); |
*n = nh; |
*n <<= 32; |
*n |= nl; |
} |
extern __inline__ void ADJUST_TIMESPEC(struct timespec *t) |
{ |
signed long long dt,dn; |
dt = t->tsc - init_tsc; |
if (dt >= 0) UNSIGNED_TSC2NSEC(dt,&dn); |
else { |
UNSIGNED_TSC2NSEC(-dt,&dn); |
dn -= dn; |
} |
t->tv_sec = dn / 1000000000; |
t->tv_nsec = dn % 1000000000; |
} |
/* |
* these macros come from the Utah Flux oskit... |
*/ |
66,64 → 132,85 |
#define TIMESPEC2NANOSEC(t) ((t)->tv_sec * 1000000000 + (t)->tv_nsec) |
#define TIMESPEC2USEC(t) ((t)->tv_sec * 1000000 + (t)->tv_nsec / 1000) |
#define NULL_TIMESPEC(t) ((t)->tv_sec = (t)->tv_nsec = 0) |
#define ADDNANO2TIMESPEC(n, t) ((t)->tv_nsec += (n), \ |
(t)->tv_sec += (t)->tv_nsec / 1000000000, \ |
(t)->tv_nsec %= 1000000000) |
#define NULL_TIMESPEC(t) ((t)->tv_sec = (t)->tv_nsec = 0, (t)->tsc = 0) |
#define SUBTIMESPEC(s1, s2, d) \ |
((d)->tv_nsec = ((s1)->tv_nsec >= (s2)->tv_nsec) ? \ |
(((d)->tv_sec = (s1)->tv_sec - (s2)->tv_sec), \ |
(s1)->tv_nsec - (s2)->tv_nsec) \ |
: \ |
(((d)->tv_sec = (s1)->tv_sec - (s2)->tv_sec - 1), \ |
(1000000000 + (s1)->tv_nsec - (s2)->tv_nsec))) |
extern __inline__ void ADDNANO2TIMESPEC(const signed long n, struct timespec *t) |
{ |
t->tv_nsec += n; |
t->tv_sec += t->tv_nsec / 1000000000; |
t->tv_nsec %= 1000000000; |
/* |
* ...and these not! |
*/ |
if (use_tsc) t->tsc += clk_per_msec * n / 1000000; |
} |
extern __inline__ void ADDUSEC2TIMESPEC(const signed long m, struct timespec *t) |
{ |
t->tv_nsec += m * 1000; |
t->tv_sec += t->tv_nsec / 1000000000; |
t->tv_nsec %= 1000000000; |
if (use_tsc) t->tsc += clk_per_msec * m / 1000; |
} |
extern __inline__ void SUBTIMESPEC(const struct timespec *s1, |
const struct timespec *s2, |
struct timespec *d) |
{ |
if (s1->tv_nsec >= s2->tv_nsec) { |
d->tv_sec = s1->tv_sec - s2->tv_sec; |
d->tv_nsec = s1->tv_nsec - s2->tv_nsec; |
} else { |
d->tv_sec = s1->tv_sec - s2->tv_sec - 1; |
d->tv_nsec = 1000000000 + s1->tv_nsec - s2->tv_nsec; |
} |
if (use_tsc) d->tsc = s1->tsc - s2->tsc + init_tsc; |
} |
extern __inline__ void ADDTIMESPEC(const struct timespec *s1, |
const struct timespec *s2, |
struct timespec *d) |
{ |
d->tv_sec = s1->tv_sec + s2->tv_sec; |
d->tv_nsec = s1->tv_nsec + s2->tv_nsec; |
d->tv_sec = s1->tv_sec + s2->tv_sec; |
d->tv_nsec = s1->tv_nsec + s2->tv_nsec; |
if (d->tv_nsec < 0) { |
d->tv_sec--; |
d->tv_nsec += 1000000000; |
} else if (d->tv_nsec >= 1000000000) { |
d->tv_sec++; |
d->tv_nsec -= 1000000000; |
} |
} |
if (d->tv_nsec < 0) { |
d->tv_sec--; |
d->tv_nsec += 1000000000; |
} else if (d->tv_nsec >= 1000000000) { |
d->tv_sec++; |
d->tv_nsec -= 1000000000; |
} |
if (use_tsc) d->tsc = s1->tsc + s2->tsc - init_tsc; |
#define ADDUSEC2TIMESPEC(m, t) ((t)->tv_nsec += (m%1000000)*1000, \ |
(t)->tv_sec += ((t)->tv_nsec / 1000000000) + (m/1000000), \ |
(t)->tv_nsec %= 1000000000) |
} |
#define TIMESPEC_A_LT_B(a,b) \ |
( \ |
((a)->tv_sec < (b)->tv_sec) || \ |
((a)->tv_sec == (b)->tv_sec && (a)->tv_nsec < (b)->tv_nsec) \ |
((a)->tv_sec == (b)->tv_sec && (a)->tv_nsec < (b)->tv_nsec) \ |
) |
#define TIMESPEC_A_GT_B(a,b) \ |
( \ |
((a)->tv_sec > (b)->tv_sec) || \ |
((a)->tv_sec == (b)->tv_sec && (a)->tv_nsec > (b)->tv_nsec) \ |
((a)->tv_sec == (b)->tv_sec && (a)->tv_nsec > (b)->tv_nsec) \ |
) |
#define TIMESPEC_A_EQ_B(a,b) \ |
((a)->tv_sec == (b)->tv_sec && (a)->tv_nsec == (b)->tv_nsec) |
#define TIMESPEC_A_NEQ_B(a,b) \ |
#define TIMESPEC_A_NEQ_B(a,b) \ |
((a)->tv_sec != (b)->tv_sec || (a)->tv_nsec != (b)->tv_nsec) |
#define TIMESPEC_ASSIGN(t1,t2) \ |
((t1)->tv_sec = (t2)->tv_sec, (t1)->tv_nsec = (t2)->tv_nsec) |
((t1)->tv_sec = (t2)->tv_sec, (t1)->tv_nsec = (t2)->tv_nsec, (t1)->tsc = (t2)->tsc) |
#if 0 |
#define PITSPEC2TIMESPEC(a,b) \ |
149,6 → 236,11 |
TIME ll_gettime(int mode, struct timespec *tsres); |
//Advanced Timer (advtimer.c) |
void read_timespec(struct timespec *tspec); |
void ll_init_advtimer(void); |
void restore_CMOS(void); |
#define TIME_PTICK 1 |
#define TIME_EXACT 2 |
#define TIME_NEW 3 |