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