Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 119 → Rev 120

/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