1 /* This file is part of the program GDB, the GNU debugger.
3 Copyright (C) 1998 Free Software Foundation, Inc.
4 Contributed by Cygnus Solutions.
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.
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.
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.
30 tx3904tmr - tx3904 timer
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.
40 Both internal and system clocks are synthesized as divided versions
41 of the simulator clock.
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)
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
69 Rate of timer clock signal. This number is the number of simulator
70 ticks per clock signal tick. Default 1.
75 Rate of "external input clock signal", the other clock input of the
76 timer. It uses the same scale as above. Default 100.
85 Interrupt port. An event is generated when a timer interrupt
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.
104 /* static functions */
106 static void deliver_tx3904tmr_tick (struct hw
*me
, void *data
);
109 /* register numbers; each is one word long */
135 static const struct hw_port_descriptor tx3904tmr_ports
[] =
137 { "int", INT_PORT
, 0, output_port
, },
138 { "ff", FF_PORT
, 0, output_port
, },
139 { "reset", RESET_PORT
, 0, input_port
, },
145 /* The timer/counter register internal state. Note that we store
146 state using the control register images, in host endian order. */
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 */
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)
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)
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)
175 #define GET_CCDR_CDR(c) (((c)->ccdr & 0x07) >> 0)
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)
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)
195 /* Finish off the partially created hw device. Attach our local
196 callbacks. Wire up our port names etc */
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
;
203 attach_tx3904tmr_regs (struct hw
*me
,
204 struct tx3904tmr
*controller
)
206 unsigned_word attach_address
;
208 unsigned attach_size
;
209 reg_property_spec reg
;
211 if (hw_find_property (me
, "reg") == NULL
)
212 hw_abort (me
, "Missing \"reg\" property");
214 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
215 hw_abort (me
, "\"reg\" property must contain one addr/size entry");
217 hw_unit_address_to_attach_address (hw_parent (me
),
222 hw_unit_size_to_attach_size (hw_parent (me
),
226 hw_attach_address (hw_parent (me
), 0,
227 attach_space
, attach_address
, attach_size
,
230 if(hw_find_property(me
, "clock") != NULL
)
231 controller
->clock_ticks
= (unsigned_4
) hw_find_integer_property(me
, "clock");
233 if(hw_find_property(me
, "ext") != NULL
)
234 controller
->ext_ticks
= (unsigned_4
) hw_find_integer_property(me
, "ext");
236 controller
->base_address
= attach_address
;
241 tx3904tmr_finish (struct hw
*me
)
243 struct tx3904tmr
*controller
;
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
);
252 /* Preset clock dividers */
253 controller
->clock_ticks
= 1;
254 controller
->ext_ticks
= 100;
256 /* Attach ourself to our parent bus */
257 attach_tx3904tmr_regs (me
, controller
);
259 /* Initialize to reset state */
267 controller
->cpra
= controller
->cprb
= 0x00FFFFFF;
269 controller
->last_ticks
= controller
->roundoff_ticks
= 0;
270 controller
->event
= NULL
;
275 /* An event arrives on an interrupt port */
278 tx3904tmr_port_event (struct hw
*me
,
284 struct tx3904tmr
*controller
= hw_data (me
);
290 HW_TRACE ((me
, "reset"));
292 /* preset flip-flop to FFI value */
293 controller
->ff
= GET_PMGR_FFI(controller
);
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
;
311 hw_abort (me
, "Event on unknown port %d", my_port
);
317 /* generic read/write */
320 tx3904tmr_io_read_buffer (struct hw
*me
,
326 struct tx3904tmr
*controller
= hw_data (me
);
329 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
330 for (byte
= 0; byte
< nr_bytes
; byte
++)
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 */
337 /* fill in entire register_value word */
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;
352 /* write requested byte out */
353 memcpy ((char*) dest
+ byte
, ((char*)& register_value
)+reg_offset
, 1);
362 tx3904tmr_io_write_buffer (struct hw
*me
,
368 struct tx3904tmr
*controller
= hw_data (me
);
371 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
372 for (byte
= 0; byte
< nr_bytes
; byte
++)
374 address_word address
= base
+ byte
;
375 unsigned_1 write_byte
= ((const char*) source
)[byte
];
376 int reg_number
= (address
- controller
->base_address
) / 4;
377 int reg_offset
= 3 - (address
- controller
->base_address
) % 4;
379 /* fill in entire register_value word */
383 if(reg_offset
== 0) /* first byte */
385 /* update register, but mask out NOP bits */
386 controller
->tcr
= (unsigned_4
) (write_byte
& 0xef);
388 /* Reset counter value if timer suspended and CRE is set. */
389 if(GET_TCR_TCE(controller
) == 0 &&
390 GET_TCR_CRE(controller
) == 1)
393 /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */
397 if(reg_offset
== 1) /* second byte */
399 SET_ITMR_TIIE(controller
, write_byte
& 0x80);
401 else if(reg_offset
== 0) /* first byte */
403 SET_ITMR_TZCE(controller
, write_byte
& 0x01);
405 /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */
409 if(reg_offset
== 0) /* first byte */
411 controller
->ccdr
= write_byte
& 0x07;
413 /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */
417 if(reg_offset
== 1) /* second byte */
419 SET_PMGR_TPIBE(controller
, write_byte
& 0x80);
420 SET_PMGR_TPIAE(controller
, write_byte
& 0x40);
422 else if(reg_offset
== 0) /* first byte */
424 SET_PMGR_FFI(controller
, write_byte
& 0x01);
426 /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */
430 if(reg_offset
== 1) /* second byte */
432 SET_WTMR_TWIE(controller
, write_byte
& 0x80);
434 else if(reg_offset
== 0) /* first byte */
436 SET_WTMR_WDIS(controller
, write_byte
& 0x80);
437 SET_WTMR_TWC(controller
, write_byte
& 0x01);
439 /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */
443 if(reg_offset
== 0) /* first byte */
445 /* All bits must be zero in given byte, according to
448 /* Send an "interrupt off" event on the interrupt port */
449 if(controller
->tisr
!= 0) /* any interrupts active? */
451 hw_port_event(me
, INT_PORT
, 0);
454 /* clear interrupt status register */
455 controller
->tisr
= 0;
457 /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */
461 if(reg_offset
< 3) /* first, second, or third byte */
463 MBLIT32(controller
->cpra
, (reg_offset
*8)+7, (reg_offset
*8), write_byte
);
465 /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */
469 if(reg_offset
< 3) /* first, second, or third byte */
471 MBLIT32(controller
->cprb
, (reg_offset
*8)+7, (reg_offset
*8), write_byte
);
473 /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */
477 HW_TRACE ((me
, "write to illegal register %d", reg_number
));
479 } /* loop over bytes */
481 /* Schedule a timer event in near future, so we can increment or
482 stop the counter, to respond to register updates. */
483 hw_event_queue_schedule(me
, 1, deliver_tx3904tmr_tick
, NULL
);
490 /* Deliver a clock tick to the counter. */
492 deliver_tx3904tmr_tick (struct hw
*me
,
495 struct tx3904tmr
*controller
= hw_data (me
);
496 SIM_DESC sd
= hw_system (me
);
497 signed_8 this_ticks
= sim_events_time(sd
);
501 signed_8 quotient
, remainder
;
503 /* compute simulation ticks between last tick and this tick */
504 if(controller
->last_ticks
!= 0)
505 warp
= this_ticks
- controller
->last_ticks
+ controller
->roundoff_ticks
;
508 controller
->last_ticks
= this_ticks
; /* initialize */
509 warp
= controller
->roundoff_ticks
;
512 if(controller
->event
!= NULL
)
513 hw_event_queue_deschedule(me
, controller
->event
);
514 controller
->event
= NULL
;
516 /* Check whether the timer ticking is enabled at this moment. This
517 largely a function of the TCE bit, but is also slightly
519 switch((int) GET_TCR_TMODE(controller
))
521 case 0: /* interval */
522 /* do not advance counter if TCE = 0 or if holding at count = CPRA */
523 if(GET_TCR_TCE(controller
) == 0 ||
524 controller
->trr
== controller
->cpra
)
528 case 1: /* pulse generator */
529 /* do not advance counter if TCE = 0 */
530 if(GET_TCR_TCE(controller
) == 0)
534 case 2: /* watchdog */
535 /* do not advance counter if TCE = 0 and WDIS = 1 */
536 if(GET_TCR_TCE(controller
) == 0 &&
537 GET_WTMR_WDIS(controller
) == 1)
541 case 3: /* disabled */
542 /* regardless of TCE, do not advance counter */
546 /* In any of the above cases that return, a subsequent register
547 write will be needed to restart the timer. A tick event is
548 scheduled by any register write, so it is more efficient not to
549 reschedule dummy events here. */
552 /* find appropriate divisor etc. */
553 if(GET_TCR_CCS(controller
) == 0) /* internal system clock */
555 /* apply internal clock divider */
556 if(GET_TCR_CCDE(controller
)) /* divisor circuit enabled? */
557 divisor
= controller
->clock_ticks
* (1 << (1 + GET_CCDR_CDR(controller
)));
559 divisor
= controller
->clock_ticks
;
563 divisor
= controller
->ext_ticks
;
566 /* how many times to increase counter? */
567 quotient
= warp
/ divisor
;
568 remainder
= warp
% divisor
;
570 /* NOTE: If the event rescheduling code works properly, the quotient
571 should never be larger than 1. That is, we should receive events
572 here at least as frequently as the simulated counter is supposed
573 to decrement. So the remainder (-> roundoff_ticks) will slowly
574 accumulate, with the quotient == 0. Once in a while, quotient
577 controller
->roundoff_ticks
= remainder
;
578 controller
->last_ticks
= this_ticks
;
579 while(quotient
> 0) /* Is it time to increment counter? */
581 /* next 24-bit counter value */
582 unsigned_4 next_trr
= (controller
->trr
+ 1) % (1 << 24);
585 switch((int) GET_TCR_TMODE(controller
))
587 case 0: /* interval timer mode */
589 /* Current or next counter value matches CPRA value? The
590 first case covers counter holding at maximum before
591 reset. The second case covers normal counting
593 if(controller
->trr
== controller
->cpra
||
594 next_trr
== controller
->cpra
)
596 /* likely hold CPRA value */
597 if(controller
->trr
== controller
->cpra
)
598 next_trr
= controller
->cpra
;
600 SET_TISR_TIIS(controller
);
602 /* Signal an interrupt if it is enabled with TIIE,
603 and if we just arrived at CPRA. Don't repeatedly
604 interrupt if holding due to TZCE=0 */
605 if(GET_ITMR_TIIE(controller
) &&
606 next_trr
!= controller
->trr
)
608 hw_port_event(me
, INT_PORT
, 1);
612 if(GET_ITMR_TZCE(controller
))
620 case 1: /* pulse generator mode */
622 /* first trip point */
623 if(next_trr
== controller
->cpra
)
625 /* flip flip-flop & report */
627 hw_port_event(me
, FF_PORT
, controller
->ff
);
628 SET_TISR_TPIAS(controller
);
630 /* signal interrupt */
631 if(GET_PMGR_TPIAE(controller
))
633 hw_port_event(me
, INT_PORT
, 1);
637 /* second trip point */
638 else if(next_trr
== controller
->cprb
)
640 /* flip flip-flop & report */
642 hw_port_event(me
, FF_PORT
, controller
->ff
);
643 SET_TISR_TPIBS(controller
);
645 /* signal interrupt */
646 if(GET_PMGR_TPIBE(controller
))
648 hw_port_event(me
, INT_PORT
, 1);
657 case 2: /* watchdog timer mode */
659 /* watchdog timer expiry */
660 if(next_trr
== controller
->cpra
)
662 SET_TISR_TWIS(controller
);
664 /* signal interrupt */
665 if(GET_WTMR_TWIE(controller
))
667 hw_port_event(me
, INT_PORT
, 1);
676 case 3: /* disabled */
681 /* update counter and report */
682 controller
->trr
= next_trr
;
683 /* HW_TRACE ((me, "counter trr %ld tisr %lx",
684 (long) controller->trr, (long) controller->tisr)); */
685 } /* end quotient loop */
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
);
696 const struct hw_descriptor dv_tx3904tmr_descriptor
[] = {
697 { "tx3904tmr", tx3904tmr_finish
, },