]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/mips/dv-tx3904tmr.c
* ECC (tx39) and sky changes.
[thirdparty/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 struct hw_event* event; /* last scheduled event */
155
156 unsigned_4 tcr;
157 #define GET_TCR_TCE(c) (((c)->tcr & 0x80) >> 7)
158 #define GET_TCR_CCDE(c) (((c)->tcr & 0x40) >> 6)
159 #define GET_TCR_CRE(c) (((c)->tcr & 0x20) >> 5)
160 #define GET_TCR_CCS(c) (((c)->tcr & 0x04) >> 2)
161 #define GET_TCR_TMODE(c) (((c)->tcr & 0x03) >> 0)
162 unsigned_4 tisr;
163 #define SET_TISR_TWIS(c) ((c)->tisr |= 0x08)
164 #define SET_TISR_TPIBS(c) ((c)->tisr |= 0x04)
165 #define SET_TISR_TPIAS(c) ((c)->tisr |= 0x02)
166 #define SET_TISR_TIIS(c) ((c)->tisr |= 0x01)
167 unsigned_4 cpra;
168 unsigned_4 cprb;
169 unsigned_4 itmr;
170 #define GET_ITMR_TIIE(c) (((c)->itmr & 0x8000) >> 15)
171 #define SET_ITMR_TIIE(c,v) BLIT32((c)->itmr, 15, (v) ? 1 : 0)
172 #define GET_ITMR_TZCE(c) (((c)->itmr & 0x0001) >> 0)
173 #define SET_ITMR_TZCE(c,v) BLIT32((c)->itmr, 0, (v) ? 1 : 0)
174 unsigned_4 ccdr;
175 #define GET_CCDR_CDR(c) (((c)->ccdr & 0x07) >> 0)
176 unsigned_4 pmgr;
177 #define GET_PMGR_TPIBE(c) (((c)->pmgr & 0x8000) >> 15)
178 #define SET_PMGR_TPIBE(c,v) BLIT32((c)->pmgr, 15, (v) ? 1 : 0)
179 #define GET_PMGR_TPIAE(c) (((c)->pmgr & 0x4000) >> 14)
180 #define SET_PMGR_TPIAE(c,v) BLIT32((c)->pmgr, 14, (v) ? 1 : 0)
181 #define GET_PMGR_FFI(c) (((c)->pmgr & 0x0001) >> 0)
182 #define SET_PMGR_FFI(c,v) BLIT32((c)->pmgr, 0, (v) ? 1 : 0)
183 unsigned_4 wtmr;
184 #define GET_WTMR_TWIE(c) (((c)->wtmr & 0x8000) >> 15)
185 #define SET_WTMR_TWIE(c,v) BLIT32((c)->wtmr, 15, (v) ? 1 : 0)
186 #define GET_WTMR_WDIS(c) (((c)->wtmr & 0x0080) >> 7)
187 #define SET_WTMR_WDIS(c,v) BLIT32((c)->wtmr, 7, (v) ? 1 : 0)
188 #define GET_WTMR_TWC(c) (((c)->wtmr & 0x0001) >> 0)
189 #define SET_WTMR_TWC(c,v) BLIT32((c)->wtmr, 0, (v) ? 1 : 0)
190 unsigned_4 trr;
191 };
192
193
194
195 /* Finish off the partially created hw device. Attach our local
196 callbacks. Wire up our port names etc */
197
198 static hw_io_read_buffer_method tx3904tmr_io_read_buffer;
199 static hw_io_write_buffer_method tx3904tmr_io_write_buffer;
200 static hw_port_event_method tx3904tmr_port_event;
201
202 static void
203 attach_tx3904tmr_regs (struct hw *me,
204 struct tx3904tmr *controller)
205 {
206 unsigned_word attach_address;
207 int attach_space;
208 unsigned attach_size;
209 reg_property_spec reg;
210
211 if (hw_find_property (me, "reg") == NULL)
212 hw_abort (me, "Missing \"reg\" property");
213
214 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
215 hw_abort (me, "\"reg\" property must contain one addr/size entry");
216
217 hw_unit_address_to_attach_address (hw_parent (me),
218 &reg.address,
219 &attach_space,
220 &attach_address,
221 me);
222 hw_unit_size_to_attach_size (hw_parent (me),
223 &reg.size,
224 &attach_size, me);
225
226 hw_attach_address (hw_parent (me), 0,
227 attach_space, attach_address, attach_size,
228 me);
229
230 if(hw_find_property(me, "clock") != NULL)
231 controller->clock_ticks = (unsigned_4) hw_find_integer_property(me, "clock");
232
233 if(hw_find_property(me, "ext") != NULL)
234 controller->ext_ticks = (unsigned_4) hw_find_integer_property(me, "ext");
235
236 controller->base_address = attach_address;
237 }
238
239
240 static void
241 tx3904tmr_finish (struct hw *me)
242 {
243 struct tx3904tmr *controller;
244
245 controller = HW_ZALLOC (me, struct tx3904tmr);
246 set_hw_data (me, controller);
247 set_hw_io_read_buffer (me, tx3904tmr_io_read_buffer);
248 set_hw_io_write_buffer (me, tx3904tmr_io_write_buffer);
249 set_hw_ports (me, tx3904tmr_ports);
250 set_hw_port_event (me, tx3904tmr_port_event);
251
252 /* Preset clock dividers */
253 controller->clock_ticks = 1;
254 controller->ext_ticks = 100;
255
256 /* Attach ourself to our parent bus */
257 attach_tx3904tmr_regs (me, controller);
258
259 /* Initialize to reset state */
260 controller->tcr =
261 controller->itmr =
262 controller->ccdr =
263 controller->pmgr =
264 controller->wtmr =
265 controller->tisr =
266 controller->trr = 0;
267 controller->cpra = controller->cprb = 0x00FFFFFF;
268 controller->ff = 0;
269 controller->last_ticks = controller->roundoff_ticks = 0;
270 controller->event = NULL;
271 }
272
273
274
275 /* An event arrives on an interrupt port */
276
277 static void
278 tx3904tmr_port_event (struct hw *me,
279 int my_port,
280 struct hw *source,
281 int source_port,
282 int level)
283 {
284 struct tx3904tmr *controller = hw_data (me);
285
286 switch (my_port)
287 {
288 case RESET_PORT:
289 {
290 HW_TRACE ((me, "reset"));
291
292 /* preset flip-flop to FFI value */
293 controller->ff = GET_PMGR_FFI(controller);
294
295 controller->tcr =
296 controller->itmr =
297 controller->ccdr =
298 controller->pmgr =
299 controller->wtmr =
300 controller->tisr =
301 controller->trr = 0;
302 controller->cpra = controller->cprb = 0x00FFFFFF;
303 controller->last_ticks = controller->roundoff_ticks = 0;
304 if(controller->event != NULL)
305 hw_event_queue_deschedule(me, controller->event);
306 controller->event = NULL;
307 break;
308 }
309
310 default:
311 hw_abort (me, "Event on unknown port %d", my_port);
312 break;
313 }
314 }
315
316
317 /* generic read/write */
318
319 static unsigned
320 tx3904tmr_io_read_buffer (struct hw *me,
321 void *dest,
322 int space,
323 unsigned_word base,
324 unsigned nr_bytes)
325 {
326 struct tx3904tmr *controller = hw_data (me);
327 unsigned byte;
328
329 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
330 for (byte = 0; byte < nr_bytes; byte++)
331 {
332 address_word address = base + byte;
333 int reg_number = (address - controller->base_address) / 4;
334 int reg_offset = 3 - (address - controller->base_address) % 4;
335 unsigned_4 register_value; /* in target byte order */
336
337 /* fill in entire register_value word */
338 switch (reg_number)
339 {
340 case TCR_REG: register_value = controller->tcr; break;
341 case TISR_REG: register_value = controller->tisr; break;
342 case CPRA_REG: register_value = controller->cpra; break;
343 case CPRB_REG: register_value = controller->cprb; break;
344 case ITMR_REG: register_value = controller->itmr; break;
345 case CCDR_REG: register_value = controller->ccdr; break;
346 case PMGR_REG: register_value = controller->pmgr; break;
347 case WTMR_REG: register_value = controller->wtmr; break;
348 case TRR_REG: register_value = controller->trr; break;
349 default: register_value = 0;
350 }
351
352 /* write requested byte out */
353 memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
354 }
355
356 return nr_bytes;
357 }
358
359
360
361 static unsigned
362 tx3904tmr_io_write_buffer (struct hw *me,
363 const void *source,
364 int space,
365 unsigned_word base,
366 unsigned nr_bytes)
367 {
368 struct tx3904tmr *controller = hw_data (me);
369 unsigned byte;
370
371 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
372 for (byte = 0; byte < nr_bytes; byte++)
373 {
374 address_word address = base + byte;
375 unsigned_1 write_byte = ((char*) source)[byte];
376 int reg_number = (address - controller->base_address) / 4;
377 int reg_offset = 3 - (address - controller->base_address) % 4;
378 unsigned_4* register_ptr;
379 unsigned_4 register_value;
380
381 /* fill in entire register_value word */
382 switch (reg_number)
383 {
384 case TCR_REG:
385 if(reg_offset == 0) /* first byte */
386 {
387 /* update register, but mask out NOP bits */
388 controller->tcr = (unsigned_4) (write_byte & 0xef);
389
390 /* Reset counter value if timer suspended and CRE is set. */
391 if(GET_TCR_TCE(controller) == 0 &&
392 GET_TCR_CRE(controller) == 1)
393 controller->trr = 0;
394 }
395 /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */
396 break;
397
398 case ITMR_REG:
399 if(reg_offset == 1) /* second byte */
400 {
401 SET_ITMR_TIIE(controller, write_byte & 0x80);
402 }
403 else if(reg_offset == 0) /* first byte */
404 {
405 SET_ITMR_TZCE(controller, write_byte & 0x01);
406 }
407 /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */
408 break;
409
410 case CCDR_REG:
411 if(reg_offset == 0) /* first byte */
412 {
413 controller->ccdr = write_byte & 0x07;
414 }
415 /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */
416 break;
417
418 case PMGR_REG:
419 if(reg_offset == 1) /* second byte */
420 {
421 SET_PMGR_TPIBE(controller, write_byte & 0x80);
422 SET_PMGR_TPIAE(controller, write_byte & 0x40);
423 }
424 else if(reg_offset == 0) /* first byte */
425 {
426 SET_PMGR_FFI(controller, write_byte & 0x01);
427 }
428 /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */
429 break;
430
431 case WTMR_REG:
432 if(reg_offset == 1) /* second byte */
433 {
434 SET_WTMR_TWIE(controller, write_byte & 0x80);
435 }
436 else if(reg_offset == 0) /* first byte */
437 {
438 SET_WTMR_WDIS(controller, write_byte & 0x80);
439 SET_WTMR_TWC(controller, write_byte & 0x01);
440 }
441 /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */
442 break;
443
444 case TISR_REG:
445 if(reg_offset == 0) /* first byte */
446 {
447 /* All bits must be zero in given byte, according to
448 spec. */
449
450 /* Send an "interrupt off" event on the interrupt port */
451 if(controller->tisr != 0) /* any interrupts active? */
452 {
453 hw_port_event(me, INT_PORT, 0);
454 }
455
456 /* clear interrupt status register */
457 controller->tisr = 0;
458 }
459 /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */
460 break;
461
462 case CPRA_REG:
463 if(reg_offset < 3) /* first, second, or third byte */
464 {
465 MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte);
466 }
467 /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */
468 break;
469
470 case CPRB_REG:
471 if(reg_offset < 3) /* first, second, or third byte */
472 {
473 MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte);
474 }
475 /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */
476 break;
477
478 default:
479 HW_TRACE ((me, "write to illegal register %d", reg_number));
480 }
481 } /* loop over bytes */
482
483 /* Schedule a timer event in near future, so we can increment or
484 stop the counter, to respond to register updates. */
485 hw_event_queue_schedule(me, 1, deliver_tx3904tmr_tick, NULL);
486
487 return nr_bytes;
488 }
489
490
491
492 /* Deliver a clock tick to the counter. */
493 static void
494 deliver_tx3904tmr_tick (struct hw *me,
495 void *data)
496 {
497 struct tx3904tmr *controller = hw_data (me);
498 SIM_DESC sd = hw_system (me);
499 signed_8 this_ticks = sim_events_time(sd);
500
501 signed_8 warp;
502 signed_8 divisor;
503 signed_8 quotient, remainder;
504
505 /* compute simulation ticks between last tick and this tick */
506 if(controller->last_ticks != 0)
507 warp = this_ticks - controller->last_ticks + controller->roundoff_ticks;
508 else
509 {
510 controller->last_ticks = this_ticks; /* initialize */
511 warp = controller->roundoff_ticks;
512 }
513
514 if(controller->event != NULL)
515 hw_event_queue_deschedule(me, controller->event);
516 controller->event = NULL;
517
518 /* Check whether the timer ticking is enabled at this moment. This
519 largely a function of the TCE bit, but is also slightly
520 mode-dependent. */
521 switch(GET_TCR_TMODE(controller))
522 {
523 case 0: /* interval */
524 /* do not advance counter if TCE = 0 or if holding at count = CPRA */
525 if(GET_TCR_TCE(controller) == 0 ||
526 controller->trr == controller->cpra)
527 return;
528 break;
529
530 case 1: /* pulse generator */
531 /* do not advance counter if TCE = 0 */
532 if(GET_TCR_TCE(controller) == 0)
533 return;
534 break;
535
536 case 2: /* watchdog */
537 /* do not advance counter if TCE = 0 and WDIS = 1 */
538 if(GET_TCR_TCE(controller) == 0 &&
539 GET_WTMR_WDIS(controller) == 1)
540 return;
541 break;
542
543 case 3: /* disabled */
544 /* regardless of TCE, do not advance counter */
545 return;
546 }
547
548 /* In any of the above cases that return, a subsequent register
549 write will be needed to restart the timer. A tick event is
550 scheduled by any register write, so it is more efficient not to
551 reschedule dummy events here. */
552
553
554 /* find appropriate divisor etc. */
555 if(GET_TCR_CCS(controller) == 0) /* internal system clock */
556 {
557 /* apply internal clock divider */
558 if(GET_TCR_CCDE(controller)) /* divisor circuit enabled? */
559 divisor = controller->clock_ticks * (1 << (1 + GET_CCDR_CDR(controller)));
560 else
561 divisor = controller->clock_ticks;
562 }
563 else
564 {
565 divisor = controller->ext_ticks;
566 }
567
568 /* how many times to increase counter? */
569 quotient = warp / divisor;
570 remainder = warp % divisor;
571
572 /* NOTE: If the event rescheduling code works properly, the quotient
573 should never be larger than 1. That is, we should receive events
574 here at least as frequently as the simulated counter is supposed
575 to decrement. So the remainder (-> roundoff_ticks) will slowly
576 accumulate, with the quotient == 0. Once in a while, quotient
577 will equal 1. */
578
579 controller->roundoff_ticks = remainder;
580 controller->last_ticks = this_ticks;
581 while(quotient > 0) /* Is it time to increment counter? */
582 {
583 /* next 24-bit counter value */
584 unsigned_4 next_trr = (controller->trr + 1) % (1 << 24);
585 quotient --;
586
587 switch(GET_TCR_TMODE(controller))
588 {
589 case 0: /* interval timer mode */
590 {
591 /* Current or next counter value matches CPRA value? The
592 first case covers counter holding at maximum before
593 reset. The second case covers normal counting
594 behavior. */
595 if(controller->trr == controller->cpra ||
596 next_trr == controller->cpra)
597 {
598 /* likely hold CPRA value */
599 if(controller->trr == controller->cpra)
600 next_trr = controller->cpra;
601
602 SET_TISR_TIIS(controller);
603
604 /* Signal an interrupt if it is enabled with TIIE,
605 and if we just arrived at CPRA. Don't repeatedly
606 interrupt if holding due to TZCE=0 */
607 if(GET_ITMR_TIIE(controller) &&
608 next_trr != controller->trr)
609 {
610 hw_port_event(me, INT_PORT, 1);
611 }
612
613 /* Reset counter? */
614 if(GET_ITMR_TZCE(controller))
615 {
616 next_trr = 0;
617 }
618 }
619 }
620 break;
621
622 case 1: /* pulse generator mode */
623 {
624 /* first trip point */
625 if(next_trr == controller->cpra)
626 {
627 /* flip flip-flop & report */
628 controller->ff ^= 1;
629 hw_port_event(me, FF_PORT, controller->ff);
630 SET_TISR_TPIAS(controller);
631
632 /* signal interrupt */
633 if(GET_PMGR_TPIAE(controller))
634 {
635 hw_port_event(me, INT_PORT, 1);
636 }
637
638 }
639 /* second trip point */
640 else if(next_trr == controller->cprb)
641 {
642 /* flip flip-flop & report */
643 controller->ff ^= 1;
644 hw_port_event(me, FF_PORT, controller->ff);
645 SET_TISR_TPIBS(controller);
646
647 /* signal interrupt */
648 if(GET_PMGR_TPIBE(controller))
649 {
650 hw_port_event(me, INT_PORT, 1);
651 }
652
653 /* clear counter */
654 next_trr = 0;
655 }
656 }
657 break;
658
659 case 2: /* watchdog timer mode */
660 {
661 /* watchdog timer expiry */
662 if(next_trr == controller->cpra)
663 {
664 SET_TISR_TWIS(controller);
665
666 /* signal interrupt */
667 if(GET_WTMR_TWIE(controller))
668 {
669 hw_port_event(me, INT_PORT, 1);
670 }
671
672 /* clear counter */
673 next_trr = 0;
674 }
675 }
676 break;
677
678 case 3: /* disabled */
679 default:
680 }
681
682 /* update counter and report */
683 controller->trr = next_trr;
684 HW_TRACE ((me, "counter trr %d tisr %x", controller->trr, controller->tisr));
685 } /* end quotient loop */
686
687 /* Reschedule a timer event in near future, so we can increment the
688 counter again. Set the event about 75% of divisor time away, so
689 we will experience roughly 1.3 events per counter increment. */
690 controller->event = hw_event_queue_schedule(me, divisor*3/4, deliver_tx3904tmr_tick, NULL);
691 }
692
693
694
695
696 const struct hw_descriptor dv_tx3904tmr_descriptor[] = {
697 { "tx3904tmr", tx3904tmr_finish, },
698 { NULL },
699 };