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