dv-tx3904tmr.c revision 1.1 1 1.1 christos /* This file is part of the program GDB, the GNU debugger.
2 1.1 christos
3 1.1 christos Copyright (C) 1998, 2007, 2008, 2009, 2010, 2011
4 1.1 christos Free Software Foundation, Inc.
5 1.1 christos Contributed by Cygnus Solutions.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>.
19 1.1 christos
20 1.1 christos */
21 1.1 christos
22 1.1 christos
23 1.1 christos #include "sim-main.h"
24 1.1 christos #include "hw-main.h"
25 1.1 christos
26 1.1 christos
27 1.1 christos /* DEVICE
28 1.1 christos
29 1.1 christos
30 1.1 christos tx3904tmr - tx3904 timer
31 1.1 christos
32 1.1 christos
33 1.1 christos DESCRIPTION
34 1.1 christos
35 1.1 christos
36 1.1 christos Implements one tx3904 timer/counter described in the tx3904
37 1.1 christos user guide. Three instances are required for TMR0, TMR1, and
38 1.1 christos TMR3 within the tx3904, at different base addresses.
39 1.1 christos
40 1.1 christos Both internal and system clocks are synthesized as divided versions
41 1.1 christos of the simulator clock.
42 1.1 christos
43 1.1 christos There is no support for:
44 1.1 christos - edge sensitivity of external clock
45 1.1 christos - different mode restrictions for TMR0..2
46 1.1 christos - level interrupts (interrupts are treated as events that occur at edges)
47 1.1 christos
48 1.1 christos
49 1.1 christos
50 1.1 christos PROPERTIES
51 1.1 christos
52 1.1 christos
53 1.1 christos reg <base> <length>
54 1.1 christos
55 1.1 christos Base of TMR control register bank. <length> must equal 0x100.
56 1.1 christos Register offsets: 0: TCR: timer control register
57 1.1 christos 4: TISR: timer interrupt status register
58 1.1 christos 8: CPRA: compare register A
59 1.1 christos 12: CPRB: compare register B
60 1.1 christos 16: ITMR: interval timer mode register
61 1.1 christos 32: CCDR: divider register
62 1.1 christos 48: PMGR: pulse generator mode register
63 1.1 christos 64: WTMR: watchdog timer mode register
64 1.1 christos 240: TRR: timer read register
65 1.1 christos
66 1.1 christos
67 1.1 christos clock <ticks>
68 1.1 christos
69 1.1 christos Rate of timer clock signal. This number is the number of simulator
70 1.1 christos ticks per clock signal tick. Default 1.
71 1.1 christos
72 1.1 christos
73 1.1 christos ext <ticks>
74 1.1 christos
75 1.1 christos Rate of "external input clock signal", the other clock input of the
76 1.1 christos timer. It uses the same scale as above. Default 100.
77 1.1 christos
78 1.1 christos
79 1.1 christos
80 1.1 christos PORTS
81 1.1 christos
82 1.1 christos
83 1.1 christos int (output)
84 1.1 christos
85 1.1 christos Interrupt port. An event is generated when a timer interrupt
86 1.1 christos occurs.
87 1.1 christos
88 1.1 christos
89 1.1 christos ff (output)
90 1.1 christos
91 1.1 christos Flip-flop output, corresponds to the TMFFOUT port. An event is
92 1.1 christos generated when flip-flop changes value. The integer associated
93 1.1 christos with the event is 1/0 according to flip-flop value.
94 1.1 christos
95 1.1 christos
96 1.1 christos reset (input)
97 1.1 christos
98 1.1 christos Reset port.
99 1.1 christos
100 1.1 christos */
101 1.1 christos
102 1.1 christos
103 1.1 christos
104 1.1 christos /* static functions */
105 1.1 christos
106 1.1 christos static void deliver_tx3904tmr_tick (struct hw *me, void *data);
107 1.1 christos
108 1.1 christos
109 1.1 christos /* register numbers; each is one word long */
110 1.1 christos enum
111 1.1 christos {
112 1.1 christos TCR_REG = 0,
113 1.1 christos TISR_REG = 1,
114 1.1 christos CPRA_REG = 2,
115 1.1 christos CPRB_REG = 3,
116 1.1 christos ITMR_REG = 4,
117 1.1 christos CCDR_REG = 8,
118 1.1 christos PMGR_REG = 12,
119 1.1 christos WTMR_REG = 16,
120 1.1 christos TRR_REG = 60
121 1.1 christos };
122 1.1 christos
123 1.1 christos
124 1.1 christos
125 1.1 christos /* port ID's */
126 1.1 christos
127 1.1 christos enum
128 1.1 christos {
129 1.1 christos RESET_PORT,
130 1.1 christos INT_PORT,
131 1.1 christos FF_PORT
132 1.1 christos };
133 1.1 christos
134 1.1 christos
135 1.1 christos static const struct hw_port_descriptor tx3904tmr_ports[] =
136 1.1 christos {
137 1.1 christos { "int", INT_PORT, 0, output_port, },
138 1.1 christos { "ff", FF_PORT, 0, output_port, },
139 1.1 christos { "reset", RESET_PORT, 0, input_port, },
140 1.1 christos { NULL, },
141 1.1 christos };
142 1.1 christos
143 1.1 christos
144 1.1 christos
145 1.1 christos /* The timer/counter register internal state. Note that we store
146 1.1 christos state using the control register images, in host endian order. */
147 1.1 christos
148 1.1 christos struct tx3904tmr {
149 1.1 christos address_word base_address; /* control register base */
150 1.1 christos unsigned_4 clock_ticks, ext_ticks; /* clock frequencies */
151 1.1 christos signed_8 last_ticks; /* time at last deliver_*_tick call */
152 1.1 christos signed_8 roundoff_ticks; /* sim ticks unprocessed during last tick call */
153 1.1 christos int ff; /* pulse generator flip-flop value: 1/0 */
154 1.1 christos struct hw_event* event; /* last scheduled event */
155 1.1 christos
156 1.1 christos unsigned_4 tcr;
157 1.1 christos #define GET_TCR_TCE(c) (((c)->tcr & 0x80) >> 7)
158 1.1 christos #define GET_TCR_CCDE(c) (((c)->tcr & 0x40) >> 6)
159 1.1 christos #define GET_TCR_CRE(c) (((c)->tcr & 0x20) >> 5)
160 1.1 christos #define GET_TCR_CCS(c) (((c)->tcr & 0x04) >> 2)
161 1.1 christos #define GET_TCR_TMODE(c) (((c)->tcr & 0x03) >> 0)
162 1.1 christos unsigned_4 tisr;
163 1.1 christos #define SET_TISR_TWIS(c) ((c)->tisr |= 0x08)
164 1.1 christos #define SET_TISR_TPIBS(c) ((c)->tisr |= 0x04)
165 1.1 christos #define SET_TISR_TPIAS(c) ((c)->tisr |= 0x02)
166 1.1 christos #define SET_TISR_TIIS(c) ((c)->tisr |= 0x01)
167 1.1 christos unsigned_4 cpra;
168 1.1 christos unsigned_4 cprb;
169 1.1 christos unsigned_4 itmr;
170 1.1 christos #define GET_ITMR_TIIE(c) (((c)->itmr & 0x8000) >> 15)
171 1.1 christos #define SET_ITMR_TIIE(c,v) BLIT32((c)->itmr, 15, (v) ? 1 : 0)
172 1.1 christos #define GET_ITMR_TZCE(c) (((c)->itmr & 0x0001) >> 0)
173 1.1 christos #define SET_ITMR_TZCE(c,v) BLIT32((c)->itmr, 0, (v) ? 1 : 0)
174 1.1 christos unsigned_4 ccdr;
175 1.1 christos #define GET_CCDR_CDR(c) (((c)->ccdr & 0x07) >> 0)
176 1.1 christos unsigned_4 pmgr;
177 1.1 christos #define GET_PMGR_TPIBE(c) (((c)->pmgr & 0x8000) >> 15)
178 1.1 christos #define SET_PMGR_TPIBE(c,v) BLIT32((c)->pmgr, 15, (v) ? 1 : 0)
179 1.1 christos #define GET_PMGR_TPIAE(c) (((c)->pmgr & 0x4000) >> 14)
180 1.1 christos #define SET_PMGR_TPIAE(c,v) BLIT32((c)->pmgr, 14, (v) ? 1 : 0)
181 1.1 christos #define GET_PMGR_FFI(c) (((c)->pmgr & 0x0001) >> 0)
182 1.1 christos #define SET_PMGR_FFI(c,v) BLIT32((c)->pmgr, 0, (v) ? 1 : 0)
183 1.1 christos unsigned_4 wtmr;
184 1.1 christos #define GET_WTMR_TWIE(c) (((c)->wtmr & 0x8000) >> 15)
185 1.1 christos #define SET_WTMR_TWIE(c,v) BLIT32((c)->wtmr, 15, (v) ? 1 : 0)
186 1.1 christos #define GET_WTMR_WDIS(c) (((c)->wtmr & 0x0080) >> 7)
187 1.1 christos #define SET_WTMR_WDIS(c,v) BLIT32((c)->wtmr, 7, (v) ? 1 : 0)
188 1.1 christos #define GET_WTMR_TWC(c) (((c)->wtmr & 0x0001) >> 0)
189 1.1 christos #define SET_WTMR_TWC(c,v) BLIT32((c)->wtmr, 0, (v) ? 1 : 0)
190 1.1 christos unsigned_4 trr;
191 1.1 christos };
192 1.1 christos
193 1.1 christos
194 1.1 christos
195 1.1 christos /* Finish off the partially created hw device. Attach our local
196 1.1 christos callbacks. Wire up our port names etc */
197 1.1 christos
198 1.1 christos static hw_io_read_buffer_method tx3904tmr_io_read_buffer;
199 1.1 christos static hw_io_write_buffer_method tx3904tmr_io_write_buffer;
200 1.1 christos static hw_port_event_method tx3904tmr_port_event;
201 1.1 christos
202 1.1 christos static void
203 1.1 christos attach_tx3904tmr_regs (struct hw *me,
204 1.1 christos struct tx3904tmr *controller)
205 1.1 christos {
206 1.1 christos unsigned_word attach_address;
207 1.1 christos int attach_space;
208 1.1 christos unsigned attach_size;
209 1.1 christos reg_property_spec reg;
210 1.1 christos
211 1.1 christos if (hw_find_property (me, "reg") == NULL)
212 1.1 christos hw_abort (me, "Missing \"reg\" property");
213 1.1 christos
214 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®))
215 1.1 christos hw_abort (me, "\"reg\" property must contain one addr/size entry");
216 1.1 christos
217 1.1 christos hw_unit_address_to_attach_address (hw_parent (me),
218 1.1 christos ®.address,
219 1.1 christos &attach_space,
220 1.1 christos &attach_address,
221 1.1 christos me);
222 1.1 christos hw_unit_size_to_attach_size (hw_parent (me),
223 1.1 christos ®.size,
224 1.1 christos &attach_size, me);
225 1.1 christos
226 1.1 christos hw_attach_address (hw_parent (me), 0,
227 1.1 christos attach_space, attach_address, attach_size,
228 1.1 christos me);
229 1.1 christos
230 1.1 christos if(hw_find_property(me, "clock") != NULL)
231 1.1 christos controller->clock_ticks = (unsigned_4) hw_find_integer_property(me, "clock");
232 1.1 christos
233 1.1 christos if(hw_find_property(me, "ext") != NULL)
234 1.1 christos controller->ext_ticks = (unsigned_4) hw_find_integer_property(me, "ext");
235 1.1 christos
236 1.1 christos controller->base_address = attach_address;
237 1.1 christos }
238 1.1 christos
239 1.1 christos
240 1.1 christos static void
241 1.1 christos tx3904tmr_finish (struct hw *me)
242 1.1 christos {
243 1.1 christos struct tx3904tmr *controller;
244 1.1 christos
245 1.1 christos controller = HW_ZALLOC (me, struct tx3904tmr);
246 1.1 christos set_hw_data (me, controller);
247 1.1 christos set_hw_io_read_buffer (me, tx3904tmr_io_read_buffer);
248 1.1 christos set_hw_io_write_buffer (me, tx3904tmr_io_write_buffer);
249 1.1 christos set_hw_ports (me, tx3904tmr_ports);
250 1.1 christos set_hw_port_event (me, tx3904tmr_port_event);
251 1.1 christos
252 1.1 christos /* Preset clock dividers */
253 1.1 christos controller->clock_ticks = 1;
254 1.1 christos controller->ext_ticks = 100;
255 1.1 christos
256 1.1 christos /* Attach ourself to our parent bus */
257 1.1 christos attach_tx3904tmr_regs (me, controller);
258 1.1 christos
259 1.1 christos /* Initialize to reset state */
260 1.1 christos controller->tcr =
261 1.1 christos controller->itmr =
262 1.1 christos controller->ccdr =
263 1.1 christos controller->pmgr =
264 1.1 christos controller->wtmr =
265 1.1 christos controller->tisr =
266 1.1 christos controller->trr = 0;
267 1.1 christos controller->cpra = controller->cprb = 0x00FFFFFF;
268 1.1 christos controller->ff = 0;
269 1.1 christos controller->last_ticks = controller->roundoff_ticks = 0;
270 1.1 christos controller->event = NULL;
271 1.1 christos }
272 1.1 christos
273 1.1 christos
274 1.1 christos
275 1.1 christos /* An event arrives on an interrupt port */
276 1.1 christos
277 1.1 christos static void
278 1.1 christos tx3904tmr_port_event (struct hw *me,
279 1.1 christos int my_port,
280 1.1 christos struct hw *source,
281 1.1 christos int source_port,
282 1.1 christos int level)
283 1.1 christos {
284 1.1 christos struct tx3904tmr *controller = hw_data (me);
285 1.1 christos
286 1.1 christos switch (my_port)
287 1.1 christos {
288 1.1 christos case RESET_PORT:
289 1.1 christos {
290 1.1 christos HW_TRACE ((me, "reset"));
291 1.1 christos
292 1.1 christos /* preset flip-flop to FFI value */
293 1.1 christos controller->ff = GET_PMGR_FFI(controller);
294 1.1 christos
295 1.1 christos controller->tcr =
296 1.1 christos controller->itmr =
297 1.1 christos controller->ccdr =
298 1.1 christos controller->pmgr =
299 1.1 christos controller->wtmr =
300 1.1 christos controller->tisr =
301 1.1 christos controller->trr = 0;
302 1.1 christos controller->cpra = controller->cprb = 0x00FFFFFF;
303 1.1 christos controller->last_ticks = controller->roundoff_ticks = 0;
304 1.1 christos if(controller->event != NULL)
305 1.1 christos hw_event_queue_deschedule(me, controller->event);
306 1.1 christos controller->event = NULL;
307 1.1 christos break;
308 1.1 christos }
309 1.1 christos
310 1.1 christos default:
311 1.1 christos hw_abort (me, "Event on unknown port %d", my_port);
312 1.1 christos break;
313 1.1 christos }
314 1.1 christos }
315 1.1 christos
316 1.1 christos
317 1.1 christos /* generic read/write */
318 1.1 christos
319 1.1 christos static unsigned
320 1.1 christos tx3904tmr_io_read_buffer (struct hw *me,
321 1.1 christos void *dest,
322 1.1 christos int space,
323 1.1 christos unsigned_word base,
324 1.1 christos unsigned nr_bytes)
325 1.1 christos {
326 1.1 christos struct tx3904tmr *controller = hw_data (me);
327 1.1 christos unsigned byte;
328 1.1 christos
329 1.1 christos HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
330 1.1 christos for (byte = 0; byte < nr_bytes; byte++)
331 1.1 christos {
332 1.1 christos address_word address = base + byte;
333 1.1 christos int reg_number = (address - controller->base_address) / 4;
334 1.1 christos int reg_offset = 3 - (address - controller->base_address) % 4;
335 1.1 christos unsigned_4 register_value; /* in target byte order */
336 1.1 christos
337 1.1 christos /* fill in entire register_value word */
338 1.1 christos switch (reg_number)
339 1.1 christos {
340 1.1 christos case TCR_REG: register_value = controller->tcr; break;
341 1.1 christos case TISR_REG: register_value = controller->tisr; break;
342 1.1 christos case CPRA_REG: register_value = controller->cpra; break;
343 1.1 christos case CPRB_REG: register_value = controller->cprb; break;
344 1.1 christos case ITMR_REG: register_value = controller->itmr; break;
345 1.1 christos case CCDR_REG: register_value = controller->ccdr; break;
346 1.1 christos case PMGR_REG: register_value = controller->pmgr; break;
347 1.1 christos case WTMR_REG: register_value = controller->wtmr; break;
348 1.1 christos case TRR_REG: register_value = controller->trr; break;
349 1.1 christos default: register_value = 0;
350 1.1 christos }
351 1.1 christos
352 1.1 christos /* write requested byte out */
353 1.1 christos memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
354 1.1 christos }
355 1.1 christos
356 1.1 christos return nr_bytes;
357 1.1 christos }
358 1.1 christos
359 1.1 christos
360 1.1 christos
361 1.1 christos static unsigned
362 1.1 christos tx3904tmr_io_write_buffer (struct hw *me,
363 1.1 christos const void *source,
364 1.1 christos int space,
365 1.1 christos unsigned_word base,
366 1.1 christos unsigned nr_bytes)
367 1.1 christos {
368 1.1 christos struct tx3904tmr *controller = hw_data (me);
369 1.1 christos unsigned byte;
370 1.1 christos
371 1.1 christos HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
372 1.1 christos for (byte = 0; byte < nr_bytes; byte++)
373 1.1 christos {
374 1.1 christos address_word address = base + byte;
375 1.1 christos unsigned_1 write_byte = ((const char*) source)[byte];
376 1.1 christos int reg_number = (address - controller->base_address) / 4;
377 1.1 christos int reg_offset = 3 - (address - controller->base_address) % 4;
378 1.1 christos
379 1.1 christos /* fill in entire register_value word */
380 1.1 christos switch (reg_number)
381 1.1 christos {
382 1.1 christos case TCR_REG:
383 1.1 christos if(reg_offset == 0) /* first byte */
384 1.1 christos {
385 1.1 christos /* update register, but mask out NOP bits */
386 1.1 christos controller->tcr = (unsigned_4) (write_byte & 0xef);
387 1.1 christos
388 1.1 christos /* Reset counter value if timer suspended and CRE is set. */
389 1.1 christos if(GET_TCR_TCE(controller) == 0 &&
390 1.1 christos GET_TCR_CRE(controller) == 1)
391 1.1 christos controller->trr = 0;
392 1.1 christos }
393 1.1 christos /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */
394 1.1 christos break;
395 1.1 christos
396 1.1 christos case ITMR_REG:
397 1.1 christos if(reg_offset == 1) /* second byte */
398 1.1 christos {
399 1.1 christos SET_ITMR_TIIE(controller, write_byte & 0x80);
400 1.1 christos }
401 1.1 christos else if(reg_offset == 0) /* first byte */
402 1.1 christos {
403 1.1 christos SET_ITMR_TZCE(controller, write_byte & 0x01);
404 1.1 christos }
405 1.1 christos /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */
406 1.1 christos break;
407 1.1 christos
408 1.1 christos case CCDR_REG:
409 1.1 christos if(reg_offset == 0) /* first byte */
410 1.1 christos {
411 1.1 christos controller->ccdr = write_byte & 0x07;
412 1.1 christos }
413 1.1 christos /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */
414 1.1 christos break;
415 1.1 christos
416 1.1 christos case PMGR_REG:
417 1.1 christos if(reg_offset == 1) /* second byte */
418 1.1 christos {
419 1.1 christos SET_PMGR_TPIBE(controller, write_byte & 0x80);
420 1.1 christos SET_PMGR_TPIAE(controller, write_byte & 0x40);
421 1.1 christos }
422 1.1 christos else if(reg_offset == 0) /* first byte */
423 1.1 christos {
424 1.1 christos SET_PMGR_FFI(controller, write_byte & 0x01);
425 1.1 christos }
426 1.1 christos /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */
427 1.1 christos break;
428 1.1 christos
429 1.1 christos case WTMR_REG:
430 1.1 christos if(reg_offset == 1) /* second byte */
431 1.1 christos {
432 1.1 christos SET_WTMR_TWIE(controller, write_byte & 0x80);
433 1.1 christos }
434 1.1 christos else if(reg_offset == 0) /* first byte */
435 1.1 christos {
436 1.1 christos SET_WTMR_WDIS(controller, write_byte & 0x80);
437 1.1 christos SET_WTMR_TWC(controller, write_byte & 0x01);
438 1.1 christos }
439 1.1 christos /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */
440 1.1 christos break;
441 1.1 christos
442 1.1 christos case TISR_REG:
443 1.1 christos if(reg_offset == 0) /* first byte */
444 1.1 christos {
445 1.1 christos /* All bits must be zero in given byte, according to
446 1.1 christos spec. */
447 1.1 christos
448 1.1 christos /* Send an "interrupt off" event on the interrupt port */
449 1.1 christos if(controller->tisr != 0) /* any interrupts active? */
450 1.1 christos {
451 1.1 christos hw_port_event(me, INT_PORT, 0);
452 1.1 christos }
453 1.1 christos
454 1.1 christos /* clear interrupt status register */
455 1.1 christos controller->tisr = 0;
456 1.1 christos }
457 1.1 christos /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */
458 1.1 christos break;
459 1.1 christos
460 1.1 christos case CPRA_REG:
461 1.1 christos if(reg_offset < 3) /* first, second, or third byte */
462 1.1 christos {
463 1.1 christos MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte);
464 1.1 christos }
465 1.1 christos /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */
466 1.1 christos break;
467 1.1 christos
468 1.1 christos case CPRB_REG:
469 1.1 christos if(reg_offset < 3) /* first, second, or third byte */
470 1.1 christos {
471 1.1 christos MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte);
472 1.1 christos }
473 1.1 christos /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */
474 1.1 christos break;
475 1.1 christos
476 1.1 christos default:
477 1.1 christos HW_TRACE ((me, "write to illegal register %d", reg_number));
478 1.1 christos }
479 1.1 christos } /* loop over bytes */
480 1.1 christos
481 1.1 christos /* Schedule a timer event in near future, so we can increment or
482 1.1 christos stop the counter, to respond to register updates. */
483 1.1 christos hw_event_queue_schedule(me, 1, deliver_tx3904tmr_tick, NULL);
484 1.1 christos
485 1.1 christos return nr_bytes;
486 1.1 christos }
487 1.1 christos
488 1.1 christos
489 1.1 christos
490 1.1 christos /* Deliver a clock tick to the counter. */
491 1.1 christos static void
492 1.1 christos deliver_tx3904tmr_tick (struct hw *me,
493 1.1 christos void *data)
494 1.1 christos {
495 1.1 christos struct tx3904tmr *controller = hw_data (me);
496 1.1 christos SIM_DESC sd = hw_system (me);
497 1.1 christos signed_8 this_ticks = sim_events_time(sd);
498 1.1 christos
499 1.1 christos signed_8 warp;
500 1.1 christos signed_8 divisor;
501 1.1 christos signed_8 quotient, remainder;
502 1.1 christos
503 1.1 christos /* compute simulation ticks between last tick and this tick */
504 1.1 christos if(controller->last_ticks != 0)
505 1.1 christos warp = this_ticks - controller->last_ticks + controller->roundoff_ticks;
506 1.1 christos else
507 1.1 christos {
508 1.1 christos controller->last_ticks = this_ticks; /* initialize */
509 1.1 christos warp = controller->roundoff_ticks;
510 1.1 christos }
511 1.1 christos
512 1.1 christos if(controller->event != NULL)
513 1.1 christos hw_event_queue_deschedule(me, controller->event);
514 1.1 christos controller->event = NULL;
515 1.1 christos
516 1.1 christos /* Check whether the timer ticking is enabled at this moment. This
517 1.1 christos largely a function of the TCE bit, but is also slightly
518 1.1 christos mode-dependent. */
519 1.1 christos switch((int) GET_TCR_TMODE(controller))
520 1.1 christos {
521 1.1 christos case 0: /* interval */
522 1.1 christos /* do not advance counter if TCE = 0 or if holding at count = CPRA */
523 1.1 christos if(GET_TCR_TCE(controller) == 0 ||
524 1.1 christos controller->trr == controller->cpra)
525 1.1 christos return;
526 1.1 christos break;
527 1.1 christos
528 1.1 christos case 1: /* pulse generator */
529 1.1 christos /* do not advance counter if TCE = 0 */
530 1.1 christos if(GET_TCR_TCE(controller) == 0)
531 1.1 christos return;
532 1.1 christos break;
533 1.1 christos
534 1.1 christos case 2: /* watchdog */
535 1.1 christos /* do not advance counter if TCE = 0 and WDIS = 1 */
536 1.1 christos if(GET_TCR_TCE(controller) == 0 &&
537 1.1 christos GET_WTMR_WDIS(controller) == 1)
538 1.1 christos return;
539 1.1 christos break;
540 1.1 christos
541 1.1 christos case 3: /* disabled */
542 1.1 christos /* regardless of TCE, do not advance counter */
543 1.1 christos return;
544 1.1 christos }
545 1.1 christos
546 1.1 christos /* In any of the above cases that return, a subsequent register
547 1.1 christos write will be needed to restart the timer. A tick event is
548 1.1 christos scheduled by any register write, so it is more efficient not to
549 1.1 christos reschedule dummy events here. */
550 1.1 christos
551 1.1 christos
552 1.1 christos /* find appropriate divisor etc. */
553 1.1 christos if(GET_TCR_CCS(controller) == 0) /* internal system clock */
554 1.1 christos {
555 1.1 christos /* apply internal clock divider */
556 1.1 christos if(GET_TCR_CCDE(controller)) /* divisor circuit enabled? */
557 1.1 christos divisor = controller->clock_ticks * (1 << (1 + GET_CCDR_CDR(controller)));
558 1.1 christos else
559 1.1 christos divisor = controller->clock_ticks;
560 1.1 christos }
561 1.1 christos else
562 1.1 christos {
563 1.1 christos divisor = controller->ext_ticks;
564 1.1 christos }
565 1.1 christos
566 1.1 christos /* how many times to increase counter? */
567 1.1 christos quotient = warp / divisor;
568 1.1 christos remainder = warp % divisor;
569 1.1 christos
570 1.1 christos /* NOTE: If the event rescheduling code works properly, the quotient
571 1.1 christos should never be larger than 1. That is, we should receive events
572 1.1 christos here at least as frequently as the simulated counter is supposed
573 1.1 christos to decrement. So the remainder (-> roundoff_ticks) will slowly
574 1.1 christos accumulate, with the quotient == 0. Once in a while, quotient
575 1.1 christos will equal 1. */
576 1.1 christos
577 1.1 christos controller->roundoff_ticks = remainder;
578 1.1 christos controller->last_ticks = this_ticks;
579 1.1 christos while(quotient > 0) /* Is it time to increment counter? */
580 1.1 christos {
581 1.1 christos /* next 24-bit counter value */
582 1.1 christos unsigned_4 next_trr = (controller->trr + 1) % (1 << 24);
583 1.1 christos quotient --;
584 1.1 christos
585 1.1 christos switch((int) GET_TCR_TMODE(controller))
586 1.1 christos {
587 1.1 christos case 0: /* interval timer mode */
588 1.1 christos {
589 1.1 christos /* Current or next counter value matches CPRA value? The
590 1.1 christos first case covers counter holding at maximum before
591 1.1 christos reset. The second case covers normal counting
592 1.1 christos behavior. */
593 1.1 christos if(controller->trr == controller->cpra ||
594 1.1 christos next_trr == controller->cpra)
595 1.1 christos {
596 1.1 christos /* likely hold CPRA value */
597 1.1 christos if(controller->trr == controller->cpra)
598 1.1 christos next_trr = controller->cpra;
599 1.1 christos
600 1.1 christos SET_TISR_TIIS(controller);
601 1.1 christos
602 1.1 christos /* Signal an interrupt if it is enabled with TIIE,
603 1.1 christos and if we just arrived at CPRA. Don't repeatedly
604 1.1 christos interrupt if holding due to TZCE=0 */
605 1.1 christos if(GET_ITMR_TIIE(controller) &&
606 1.1 christos next_trr != controller->trr)
607 1.1 christos {
608 1.1 christos hw_port_event(me, INT_PORT, 1);
609 1.1 christos }
610 1.1 christos
611 1.1 christos /* Reset counter? */
612 1.1 christos if(GET_ITMR_TZCE(controller))
613 1.1 christos {
614 1.1 christos next_trr = 0;
615 1.1 christos }
616 1.1 christos }
617 1.1 christos }
618 1.1 christos break;
619 1.1 christos
620 1.1 christos case 1: /* pulse generator mode */
621 1.1 christos {
622 1.1 christos /* first trip point */
623 1.1 christos if(next_trr == controller->cpra)
624 1.1 christos {
625 1.1 christos /* flip flip-flop & report */
626 1.1 christos controller->ff ^= 1;
627 1.1 christos hw_port_event(me, FF_PORT, controller->ff);
628 1.1 christos SET_TISR_TPIAS(controller);
629 1.1 christos
630 1.1 christos /* signal interrupt */
631 1.1 christos if(GET_PMGR_TPIAE(controller))
632 1.1 christos {
633 1.1 christos hw_port_event(me, INT_PORT, 1);
634 1.1 christos }
635 1.1 christos
636 1.1 christos }
637 1.1 christos /* second trip point */
638 1.1 christos else if(next_trr == controller->cprb)
639 1.1 christos {
640 1.1 christos /* flip flip-flop & report */
641 1.1 christos controller->ff ^= 1;
642 1.1 christos hw_port_event(me, FF_PORT, controller->ff);
643 1.1 christos SET_TISR_TPIBS(controller);
644 1.1 christos
645 1.1 christos /* signal interrupt */
646 1.1 christos if(GET_PMGR_TPIBE(controller))
647 1.1 christos {
648 1.1 christos hw_port_event(me, INT_PORT, 1);
649 1.1 christos }
650 1.1 christos
651 1.1 christos /* clear counter */
652 1.1 christos next_trr = 0;
653 1.1 christos }
654 1.1 christos }
655 1.1 christos break;
656 1.1 christos
657 1.1 christos case 2: /* watchdog timer mode */
658 1.1 christos {
659 1.1 christos /* watchdog timer expiry */
660 1.1 christos if(next_trr == controller->cpra)
661 1.1 christos {
662 1.1 christos SET_TISR_TWIS(controller);
663 1.1 christos
664 1.1 christos /* signal interrupt */
665 1.1 christos if(GET_WTMR_TWIE(controller))
666 1.1 christos {
667 1.1 christos hw_port_event(me, INT_PORT, 1);
668 1.1 christos }
669 1.1 christos
670 1.1 christos /* clear counter */
671 1.1 christos next_trr = 0;
672 1.1 christos }
673 1.1 christos }
674 1.1 christos break;
675 1.1 christos
676 1.1 christos case 3: /* disabled */
677 1.1 christos default:
678 1.1 christos break;
679 1.1 christos }
680 1.1 christos
681 1.1 christos /* update counter and report */
682 1.1 christos controller->trr = next_trr;
683 1.1 christos /* HW_TRACE ((me, "counter trr %ld tisr %lx",
684 1.1 christos (long) controller->trr, (long) controller->tisr)); */
685 1.1 christos } /* end quotient loop */
686 1.1 christos
687 1.1 christos /* Reschedule a timer event in near future, so we can increment the
688 1.1 christos counter again. Set the event about 75% of divisor time away, so
689 1.1 christos we will experience roughly 1.3 events per counter increment. */
690 1.1 christos controller->event = hw_event_queue_schedule(me, divisor*3/4, deliver_tx3904tmr_tick, NULL);
691 1.1 christos }
692 1.1 christos
693 1.1 christos
694 1.1 christos
695 1.1 christos
696 1.1 christos const struct hw_descriptor dv_tx3904tmr_descriptor[] = {
697 1.1 christos { "tx3904tmr", tx3904tmr_finish, },
698 1.1 christos { NULL },
699 1.1 christos };
700