fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/simarm/timer.c *
7 * Created: 2004-11-14 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2013 Hampa Hug <hampa@hampa.ch> *
9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> *
10 *****************************************************************************/
11
12/*****************************************************************************
13 * This program is free software. You can redistribute it and / or modify it *
14 * under the terms of the GNU General Public License version 2 as published *
15 * by the Free Software Foundation. *
16 * *
17 * This program is distributed in the hope that it will be useful, but *
18 * WITHOUT ANY WARRANTY, without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
20 * Public License for more details. *
21 *****************************************************************************/
22
23/*****************************************************************************
24 * This software was developed at the Computer Engineering and Networks *
25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. *
26 *****************************************************************************/
27
28
29#include "main.h"
30#include "timer.h"
31
32#include <stdlib.h>
33
34#include <lib/log.h>
35
36
37#define IXP_TIMER_ACT (1UL << 7)
38
39
40static unsigned char tmr_get_uint8 (ixp_timer_t *ic, unsigned long addr);
41static unsigned short tmr_get_uint16 (ixp_timer_t *ic, unsigned long addr);
42static unsigned long tmr_get_uint32 (ixp_timer_t *ic, unsigned long addr);
43static void tmr_set_uint8 (ixp_timer_t *ic, unsigned long addr, unsigned char val);
44static void tmr_set_uint16 (ixp_timer_t *ic, unsigned long addr, unsigned short val);
45static void tmr_set_uint32 (ixp_timer_t *ic, unsigned long addr, unsigned long val);
46
47
48static
49void ctr_init (ixp_timer_counter_t *ctr)
50{
51 ctr->clock = NULL;
52
53 ctr->irq = NULL;
54 ctr->irq_ext = NULL;
55 ctr->irq_val = 0;
56
57 ctr->ctrl = 0;
58 ctr->load = 0xffffffffUL;
59 ctr->status = 0;
60 ctr->clear = 0;
61
62 ctr->clkdiv = 0;
63}
64
65static
66void ctr_set_irq (ixp_timer_counter_t *ctr, unsigned char val)
67{
68 if (val) {
69 if ((ctr->irq != NULL) && (ctr->irq_val == 0)) {
70 ctr->irq (ctr->irq_ext, 1);
71 ctr->irq_val = 1;
72 }
73 }
74 else {
75 if ((ctr->irq != NULL) && (ctr->irq_val != 0)) {
76 ctr->irq (ctr->irq_ext, 0);
77 ctr->irq_val = 0;
78 }
79 }
80}
81
82static
83void ctr_clock_1 (ixp_timer_counter_t *ctr, unsigned long n)
84{
85 if (ctr->status == 0) {
86 ctr->status = ctr->load;
87 }
88
89 if (n < ctr->status) {
90 ctr->status -= n;
91 return;
92 }
93
94 n -= ctr->status;
95
96 while (n > ctr->load) {
97 n -= ctr->load;
98 n -= 1;
99 }
100
101 ctr->status = ctr->load - n;
102
103 ctr_set_irq (ctr, 1);
104}
105
106static
107void ctr_clock_16 (ixp_timer_counter_t *ctr, unsigned long n)
108{
109 n += ctr->clkdiv;
110
111 ctr->clkdiv = n % 16;
112
113 ctr_clock_1 (ctr, n / 16);
114}
115
116static
117void ctr_clock_256 (ixp_timer_counter_t *ctr, unsigned long n)
118{
119 n += ctr->clkdiv;
120
121 ctr->clkdiv = n % 256;
122
123 ctr_clock_1 (ctr, n / 256);
124}
125
126static
127void ctr_set_ctrl (ixp_timer_counter_t *ctr, unsigned long val)
128{
129 ctr->ctrl = val & 0x0000008cUL;
130
131 switch ((val >> 2) & 0x03) {
132 case 0x00:
133 ctr->clock = ctr_clock_1;
134 break;
135
136 case 0x01:
137 ctr->clock = ctr_clock_16;
138 break;
139
140 case 0x02:
141 ctr->clock = ctr_clock_256;
142 break;
143
144 case 0x03:
145 ctr->clock = ctr_clock_1;
146 break;
147 }
148
149 if ((ctr->ctrl & IXP_TIMER_ACT) == 0) {
150 ctr->clock = NULL;
151 }
152}
153
154static
155void ctr_set_load (ixp_timer_counter_t *ctr, unsigned long val)
156{
157 ctr->load = val;
158 ctr->status = val;
159}
160
161static
162void ctr_set_clear (ixp_timer_counter_t *ctr, unsigned long val)
163{
164 ctr->clear = val;
165 ctr_set_irq (ctr, 0);
166}
167
168static
169unsigned long ctr_get_ctrl (ixp_timer_counter_t *ctr)
170{
171 return (ctr->ctrl);
172}
173
174static
175unsigned long ctr_get_load (ixp_timer_counter_t *ctr)
176{
177 return (ctr->load);
178}
179
180static
181unsigned long ctr_get_status (ixp_timer_counter_t *ctr)
182{
183 return (ctr->status);
184}
185
186void tmr_init (ixp_timer_t *tmr, unsigned long base)
187{
188 unsigned i;
189
190 tmr->base = base;
191
192 mem_blk_init (&tmr->io, base, 0x00010000UL, 0);
193 tmr->io.ext = tmr;
194 tmr->io.get_uint8 = (mem_get_uint8_f) tmr_get_uint8;
195 tmr->io.set_uint8 = (mem_set_uint8_f) tmr_set_uint8;
196 tmr->io.get_uint16 = (mem_get_uint16_f) tmr_get_uint16;
197 tmr->io.set_uint16 = (mem_set_uint16_f) tmr_set_uint16;
198 tmr->io.get_uint32 = (mem_get_uint32_f) tmr_get_uint32;
199 tmr->io.set_uint32 = (mem_set_uint32_f) tmr_set_uint32;
200
201 for (i = 0; i < 4; i++) {
202 ctr_init (&tmr->cntr[i]);
203 }
204
205 tmr->twde = 0;
206}
207
208ixp_timer_t *tmr_new (unsigned long base)
209{
210 ixp_timer_t *tmr;
211
212 tmr = malloc (sizeof (ixp_timer_t));
213 if (tmr == NULL) {
214 return (NULL);
215 }
216
217 tmr_init (tmr, base);
218
219 return (tmr);
220}
221
222void tmr_free (ixp_timer_t *tmr)
223{
224 mem_blk_free (&tmr->io);
225}
226
227void tmr_del (ixp_timer_t *tmr)
228{
229 if (tmr != NULL) {
230 tmr_free (tmr);
231 free (tmr);
232 }
233}
234
235mem_blk_t *tmr_get_io (ixp_timer_t *tmr, unsigned i)
236{
237 if (i == 0) {
238 return (&tmr->io);
239 }
240
241 return (NULL);
242}
243
244int tmr_get_active (ixp_timer_t *tmr, unsigned i)
245{
246 if (i <= 3) {
247 if (tmr->cntr[i].ctrl & IXP_TIMER_ACT) {
248 return (1);
249 }
250 }
251
252 return (0);
253}
254
255void tmr_set_irq_f (ixp_timer_t *tmr, unsigned i, void *f, void *ext)
256{
257 if (i < 4) {
258 tmr->cntr[i].irq = f;
259 tmr->cntr[i].irq_ext = ext;
260 }
261}
262
263static
264unsigned char tmr_get_uint8 (ixp_timer_t *tmr, unsigned long addr)
265{
266 pce_log (MSG_DEB, "TMR: get_uint8 (%08lX)\n", addr);
267
268 return (0);
269}
270
271static
272unsigned short tmr_get_uint16 (ixp_timer_t *tmr, unsigned long addr)
273{
274 pce_log (MSG_DEB, "TMR: get_uint16 (%08lX)\n", addr);
275
276 return (0);
277}
278
279static
280unsigned long tmr_get_uint32 (ixp_timer_t *tmr, unsigned long addr)
281{
282 switch (addr) {
283 case 0x00:
284 case 0x04:
285 case 0x08:
286 case 0x0c:
287 return (ctr_get_ctrl (&tmr->cntr[(addr >> 2) & 0x03]));
288
289 case 0x10:
290 case 0x14:
291 case 0x18:
292 case 0x1c:
293 return (ctr_get_load (&tmr->cntr[(addr >> 2) & 0x03]));
294
295 case 0x20:
296 case 0x24:
297 case 0x28:
298 case 0x2c:
299 return (ctr_get_status (&tmr->cntr[(addr >> 2) & 0x03]));
300 }
301
302 return (0);
303}
304
305static
306void tmr_set_uint8 (ixp_timer_t *tmr, unsigned long addr, unsigned char val)
307{
308 pce_log (MSG_DEB, "TMR: set_uint8 (%08lX, %02X)\n", addr, (unsigned) val);
309}
310
311static
312void tmr_set_uint16 (ixp_timer_t *tmr, unsigned long addr, unsigned short val)
313{
314 pce_log (MSG_DEB, "TMR: set_uint16 (%08lX, %04X)\n", addr, (unsigned) val);
315}
316
317static
318void tmr_set_uint32 (ixp_timer_t *tmr, unsigned long addr, unsigned long val)
319{
320 switch (addr) {
321 case 0x00:
322 case 0x04:
323 case 0x08:
324 case 0x0c:
325 ctr_set_ctrl (&tmr->cntr[(addr >> 2) & 0x03], val);
326 break;
327
328 case 0x10:
329 case 0x14:
330 case 0x18:
331 case 0x1c:
332 ctr_set_load (&tmr->cntr[(addr >> 2) & 0x03], val);
333 break;
334
335 case 0x30:
336 case 0x34:
337 case 0x38:
338 case 0x3c:
339 ctr_set_clear (&tmr->cntr[(addr >> 2) & 0x03], val);
340 break;
341 }
342}
343
344void tmr_clock (ixp_timer_t *tmr, unsigned long n)
345{
346 unsigned i;
347 ixp_timer_counter_t *c;
348
349 for (i = 0; i < 4; i++) {
350 c = &tmr->cntr[i];
351
352 if (c->clock != NULL) {
353 c->clock (c, n);
354 }
355 }
356}