* ECC (tx39) and sky changes.
[platform/upstream/binutils.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 };