SayoriOS 0.3.3

timer.c
1 #include "timer.h"
2 #include "interrupt.h"
3 #include "cpu.h"
4
5 static unsigned int prev_time;
6 static unsigned short ticks = 0;
7 static unsigned int reload;
8 static unsigned int reloaded;
9
10 static unsigned char tac;
11 static unsigned int started;
12 static unsigned int speed;
13 static unsigned short counter;
14 static unsigned int modulo;
15
16 /* Any write to this register resets the timer */
17 void timer_set_div(unsigned char v)
18 {
19 (void) v;
20 unsigned int bit;
21
22 bit = speed >> 1;
23
24 /* Counter is incremented if the high bit transitions 1->0 */
25 if(ticks & bit)
26 {
27 counter++;
28 if(counter == 0x100)
29 {
30 counter = 0;
31 reload = 1;
32 }
33 }
34 ticks = 0;
35 }
36
37 unsigned char timer_get_div(void)
38 {
39 return ticks>>8;
40 }
41
42 void timer_set_counter(unsigned char v)
43 {
44 if(reload)
45 reload = 0;
46 if(!reloaded)
47 counter = v;
48 }
49
50 unsigned char timer_get_counter(void)
51 {
52 return counter;
53 }
54
55 void timer_set_modulo(unsigned char v)
56 {
57 if(reloaded)
58 counter = v;
59 modulo = v;
60 }
61
62 unsigned char timer_get_modulo(void)
63 {
64 return modulo;
65 }
66
67 void timer_set_tac(unsigned char v)
68 {
69 int speeds[] = {1024, 16, 64, 256};
70
71 tac = v;
72
73 /* TAC high -> low */
74 if(started && !(v&4))
75 {
76 if(ticks & (speed >> 1))
77 {
78 counter++;
79 if(counter == 0x100)
80 {
81 counter = 0;
82 reload = 1;
83 }
84 }
85 }
86
87 if(ticks & (speed >> 1) && !(ticks & (speeds[v&3]>>1)))
88 {
89 counter++;
90 if(counter == 0x100)
91 {
92 counter = 0;
93 reload = 1;
94 }
95 }
96
97 started = v&4;
98 speed = speeds[v&3];
99 }
100
101 unsigned char timer_get_tac(void)
102 {
103 return tac;
104 }
105
106 static void timer_tick(int delta)
107 {
108 while(delta--)
109 {
110 unsigned int old_ticks;
111
112 reloaded = 0;
113
114 /* Delays the counter reload by a tick */
115 if(reload)
116 {
117 reload = 0;
118 counter = modulo;
119 reloaded = 1;
120 interrupt(INTR_TIMER);
121 }
122
123 old_ticks = ticks;
124 /* Our CPU runs at 1MHz, timer is 4MHz */
125 ticks += 4;
126
127 if(!started)
128 continue;
129
130 if(((old_ticks & (speed>>1)))
131 && (ticks & (speed>>1)) == 0)
132 counter++;
133
134 if(counter == 0x100)
135 {
136 counter = 0;
137 reload = 1;
138 }
139 }
140 }
141
142 void timer_cycle(void)
143 {
144 /* The amount of ticks since we last ran */
145 unsigned int delta;
146
147 delta = cpu_get_cycles() - prev_time;
148 prev_time = cpu_get_cycles();
149
150 timer_tick(delta);
151 }