1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#include "u.h"
#include "ureg.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
extern uchar *periph;
ulong *global, *local;
enum {
PERIPHCLK = 506965000,
MaxPeriod = PERIPHCLK / (256 * 100),
MinPeriod = MaxPeriod / 100,
} ;
void
globalclockinit(void)
{
global = (ulong*) (periph + 0x200);
local = (ulong*) (periph + 0x600);
global[2] &= 0xFFFF00F0;
global[0] = 0;
global[1] = 0;
global[2] |= 1;
}
void
cycles(uvlong *x)
{
ulong hi, newhi, lo, *y;
newhi = global[1];
do{
hi = newhi;
lo = global[0];
}while((newhi = global[1]) != hi);
y = (ulong *) x;
y[0] = lo;
y[1] = hi;
}
uvlong
fastticks(uvlong *hz)
{
uvlong ret;
if(hz != nil)
*hz = PERIPHCLK;
cycles(&ret);
return ret;
}
ulong
µs(void)
{
return fastticks2us(fastticks(nil));
}
ulong
perfticks(void)
{
return global[0];
}
void
clocktick(Ureg* ureg, void *)
{
timerintr(ureg, 0);
}
void
localclockinit(void)
{
local[2] = 0xFF06;
intenable(29, clocktick, nil);
timerset(0);
}
void
timerset(uvlong val)
{
uvlong now, ticks;
if(val == 0)
ticks = MaxPeriod;
else{
cycles(&now);
ticks = (val - now) / 256;
if(ticks < MinPeriod)
ticks = MinPeriod;
if(ticks > MaxPeriod)
ticks = MaxPeriod;
}
local[2] &= ~1;
local[0] = local[1] = ticks;
local[2] |= 1;
}
static void
waituntil(uvlong n)
{
uvlong now, then;
cycles(&now);
then = now + n;
while(now < then)
cycles(&now);
}
void
microdelay(int n)
{
waituntil(((uvlong)n) * PERIPHCLK / 1000000);
}
void
delay(int n)
{
waituntil(((uvlong)n) * PERIPHCLK / 1000);
}
|