xref: /inferno-os/os/rpcg/clock.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"ureg.h"
8 
9 #include	<isa.h>
10 #include	<interp.h>
11 
12 typedef struct Clock0link Clock0link;
13 typedef struct Clock0link {
14 	void		(*clock)(void);
15 	Clock0link*	link;
16 } Clock0link;
17 
18 static Clock0link *clock0link;
19 static Lock clock0lock;
20 ulong	clkrelinq;
21 void	(*kproftick)(ulong);	/* set by devkprof.c when active */
22 void	(*archclocktick)(void);	/* set by arch*.c when desired */
23 
24 Timer*
25 addclock0link(void (*clock)(void), int)
26 {
27 	Clock0link *lp;
28 
29 	if((lp = malloc(sizeof(Clock0link))) == 0){
30 		print("addclock0link: too many links\n");
31 		return nil;
32 	}
33 	ilock(&clock0lock);
34 	lp->clock = clock;
35 	lp->link = clock0link;
36 	clock0link = lp;
37 	iunlock(&clock0lock);
38 	return nil;
39 }
40 
41 void
42 delay(int l)
43 {
44 	ulong i, j;
45 
46 	j = m->delayloop;
47 	while(l-- > 0)
48 		for(i=0; i < j; i++)
49 			;
50 }
51 
52 void
53 microdelay(int l)
54 {
55 	ulong i;
56 
57 	l *= m->delayloop;
58 	l /= 1000;
59 	if(l <= 0)
60 		l = 1;
61 	for(i = 0; i < l; i++)
62 		;
63 }
64 
65 enum {
66 	Timebase = 2,	/* system clock cycles per time base cycle */
67 };
68 
69 static	ulong	clkreload;
70 
71 void
72 clockinit(void)
73 {
74 	long x;
75 
76 	m->delayloop = m->cpuhz/1000;	/* initial estimate */
77 	do {
78 		x = gettbl();
79 		delay(10);
80 		x = gettbl() - x;
81 	} while(x < 0);
82 
83 	/*
84 	 *  fix count
85 	 */
86 	m->delayloop = ((vlong)m->delayloop*(10*m->clockgen/1000))/(x*Timebase);
87 	if(m->delayloop == 0)
88 		m->delayloop = 1;
89 
90 	clkreload = (m->clockgen/Timebase)/HZ-1;
91 	putdec(clkreload);
92 }
93 
94 void
95 clockintr(Ureg *ur)
96 {
97 	Clock0link *lp;
98 	long v;
99 
100 	v = -getdec();
101 	if(v > clkreload/2){
102 		if(v > clkreload)
103 			m->ticks += v/clkreload;
104 		v = 0;
105 	}
106 	putdec(clkreload-v);
107 
108 	/* watchdog */
109 	if(m->iomem->sypcr & (1<<2)){
110 		m->iomem->swsr = 0x556c;
111 		m->iomem->swsr = 0xaa39;
112 	}
113 
114 	m->ticks++;
115 	if(archclocktick != nil)
116 		archclocktick();
117 
118 	if(up)
119 		up->pc = ur->pc;
120 
121 	checkalarms();
122 	if(m->machno == 0) {
123 		if(kproftick != nil)
124 			(*kproftick)(ur->pc);
125 		if(canlock(&clock0lock)){
126 			for(lp = clock0link; lp; lp = lp->link)
127 				lp->clock();
128 			unlock(&clock0lock);
129 		}
130 	}
131 
132 	if(up && up->state == Running){
133 		if(cflag && up->type == Interp && tready(nil))
134 			ur->cr |= 1;	/* set flag in condition register for ../../libinterp/comp-power.c:/^schedcheck */
135 	}
136 	/* other preemption checks are done by trap.c */
137 }
138 
139 uvlong
140 fastticks(uvlong *hz)
141 {
142 	if(hz)
143 		*hz = HZ;
144 	return m->ticks;
145 }
146