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