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 }