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