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