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 "../port/error.h"
8 #include "msaturn.h"
9
10 enum {
11 Timer_ctrl = Saturn + 0x0106,
12 Timer0_load = Saturn + 0x0200,
13 Timer0_cnt = Saturn + 0x0204,
14 Timer1_load = Saturn + 0x0300,
15 Timer1_cnt = Saturn + 0x0304,
16
17 T0_event = RBIT(13, ushort),
18 T0_ie = RBIT(14, ushort),
19 T0_cen = RBIT(15, ushort),
20 T1_event = RBIT(5, ushort),
21 T1_ie = RBIT(6, ushort),
22 T1_cen = RBIT(7, ushort),
23 };
24
25 static ulong ticks;
26 static Lock tlock;
27 static ushort timer_ctl;
28
29 ulong multiplier;
30
31 ulong
s(void)32 µs(void)
33 {
34 uvlong x;
35
36 if(multiplier == 0){
37 multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq;
38 print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16);
39 }
40 cycles(&x);
41 return (x*multiplier) >> 16;
42 }
43
44 void
saturntimerintr(Ureg * u,void *)45 saturntimerintr(Ureg *u, void*)
46 {
47 ushort ctl = *(ushort*)Timer_ctrl, v = 0;
48
49 if(ctl&T1_event){
50 v = T1_event;
51 ticks++;
52 }
53
54 *(ushort*)Timer_ctrl = timer_ctl|T0_event|v;
55 intack();
56 timerintr(u, 0);
57 }
58
59 void
timerinit(void)60 timerinit(void)
61 {
62 *(ushort*)Timer_ctrl = 0;
63 *(ulong*)Timer0_load = m->bushz / HZ;
64 *(ulong*)Timer0_cnt = m->bushz / HZ;
65 *(ulong*)Timer1_load = m->bushz;
66 *(ulong*)Timer1_cnt = m->bushz;
67
68 intrenable(Vectimer0, saturntimerintr, nil, "timer");
69
70 timer_ctl = T0_cen|T0_ie|T1_cen;
71 *(ushort*)Timer_ctrl = timer_ctl;
72 }
73
74 uvlong
fastticks(uvlong * hz)75 fastticks(uvlong *hz)
76 {
77 assert(*(ushort*)Timer_ctrl&T1_cen);
78 if(*(ushort*)Timer_ctrl&T1_event){
79 *(ushort*)Timer_ctrl = timer_ctl|T1_event;
80 ticks++;
81 }
82
83 if (hz)
84 *hz = m->bushz;
85
86 return (uvlong)ticks*m->bushz+(uvlong)(m->bushz-*(ulong*)Timer1_cnt);
87 }
88
89 void
timerset(Tval next)90 timerset(Tval next)
91 {
92 ulong offset;
93 uvlong now;
94
95 ilock(&tlock);
96 *(ushort*)Timer_ctrl = T1_cen;
97
98 now = fastticks(nil);
99 offset = next - now;
100 if((long)offset < 10000)
101 offset = 10000;
102 else if(offset > m->bushz)
103 offset = m->bushz;
104
105 *(ulong*)Timer0_cnt = offset;
106 *(ushort*)Timer_ctrl = timer_ctl;
107 assert(*(ushort*)Timer_ctrl & T1_cen);
108 iunlock(&tlock);
109 }
110
111