Home | History | Annotate | Line # | Download | only in mips
dv-tx3904tmr.c revision 1.1
      1 /*  This file is part of the program GDB, the GNU debugger.
      2 
      3     Copyright (C) 1998, 2007, 2008, 2009, 2010, 2011
      4     Free Software Foundation, Inc.
      5     Contributed by Cygnus Solutions.
      6 
      7     This program is free software; you can redistribute it and/or modify
      8     it under the terms of the GNU General Public License as published by
      9     the Free Software Foundation; either version 3 of the License, or
     10     (at your option) any later version.
     11 
     12     This program is distributed in the hope that it will be useful,
     13     but WITHOUT ANY WARRANTY; without even the implied warranty of
     14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15     GNU General Public License for more details.
     16 
     17     You should have received a copy of the GNU General Public License
     18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     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 = ((const char*) source)[byte];
    376       int reg_number = (address - controller->base_address) / 4;
    377       int reg_offset = 3 - (address - controller->base_address) % 4;
    378 
    379       /* fill in entire register_value word */
    380       switch (reg_number)
    381 	{
    382 	case TCR_REG:
    383 	  if(reg_offset == 0) /* first byte */
    384 	    {
    385 	      /* update register, but mask out NOP bits */
    386 	      controller->tcr = (unsigned_4) (write_byte & 0xef);
    387 
    388 	      /* Reset counter value if timer suspended and CRE is set. */
    389 	      if(GET_TCR_TCE(controller) == 0 &&
    390 		 GET_TCR_CRE(controller) == 1)
    391 		controller->trr = 0;
    392 	    }
    393 	  /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */
    394 	  break;
    395 
    396 	case ITMR_REG:
    397 	  if(reg_offset == 1) /* second byte */
    398 	    {
    399 	      SET_ITMR_TIIE(controller, write_byte & 0x80);
    400 	    }
    401 	  else if(reg_offset == 0) /* first byte */
    402 	    {
    403 	      SET_ITMR_TZCE(controller, write_byte & 0x01);
    404 	    }
    405 	  /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */
    406 	  break;
    407 
    408 	case CCDR_REG:
    409 	  if(reg_offset == 0) /* first byte */
    410 	    {
    411 	      controller->ccdr = write_byte & 0x07;
    412 	    }
    413 	  /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */
    414 	  break;
    415 
    416 	case PMGR_REG:
    417 	  if(reg_offset == 1) /* second byte */
    418 	    {
    419 	      SET_PMGR_TPIBE(controller, write_byte & 0x80);
    420 	      SET_PMGR_TPIAE(controller, write_byte & 0x40);
    421 	    }
    422 	  else if(reg_offset == 0) /* first byte */
    423 	    {
    424 	      SET_PMGR_FFI(controller, write_byte & 0x01);
    425 	    }
    426 	  /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */
    427 	  break;
    428 
    429 	case WTMR_REG:
    430 	  if(reg_offset == 1) /* second byte */
    431 	    {
    432 	      SET_WTMR_TWIE(controller, write_byte & 0x80);
    433 	    }
    434 	  else if(reg_offset == 0) /* first byte */
    435 	    {
    436 	      SET_WTMR_WDIS(controller, write_byte & 0x80);
    437 	      SET_WTMR_TWC(controller, write_byte & 0x01);
    438 	    }
    439 	  /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */
    440 	  break;
    441 
    442 	case TISR_REG:
    443 	  if(reg_offset == 0) /* first byte */
    444 	    {
    445 	      /* All bits must be zero in given byte, according to
    446                  spec. */
    447 
    448 	      /* Send an "interrupt off" event on the interrupt port */
    449 	      if(controller->tisr != 0) /* any interrupts active? */
    450 		{
    451 		  hw_port_event(me, INT_PORT, 0);
    452 		}
    453 
    454 	      /* clear interrupt status register */
    455 	      controller->tisr = 0;
    456 	    }
    457 	  /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */
    458 	  break;
    459 
    460 	case CPRA_REG:
    461 	  if(reg_offset < 3) /* first, second, or third byte */
    462 	    {
    463 	      MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte);
    464 	    }
    465 	  /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */
    466 	  break;
    467 
    468 	case CPRB_REG:
    469 	  if(reg_offset < 3) /* first, second, or third byte */
    470 	    {
    471 	      MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte);
    472 	    }
    473 	  /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */
    474 	  break;
    475 
    476 	default:
    477 	  HW_TRACE ((me, "write to illegal register %d", reg_number));
    478 	}
    479     } /* loop over bytes */
    480 
    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);
    484 
    485   return nr_bytes;
    486 }
    487 
    488 
    489 
    490 /* Deliver a clock tick to the counter. */
    491 static void
    492 deliver_tx3904tmr_tick (struct hw *me,
    493 			void *data)
    494 {
    495   struct tx3904tmr *controller = hw_data (me);
    496   SIM_DESC sd = hw_system (me);
    497   signed_8 this_ticks = sim_events_time(sd);
    498 
    499   signed_8 warp;
    500   signed_8 divisor;
    501   signed_8 quotient, remainder;
    502 
    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;
    506   else
    507     {
    508       controller->last_ticks = this_ticks; /* initialize */
    509       warp = controller->roundoff_ticks;
    510     }
    511 
    512   if(controller->event != NULL)
    513     hw_event_queue_deschedule(me, controller->event);
    514   controller->event = NULL;
    515 
    516   /* Check whether the timer ticking is enabled at this moment.  This
    517      largely a function of the TCE bit, but is also slightly
    518      mode-dependent. */
    519   switch((int) GET_TCR_TMODE(controller))
    520     {
    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)
    525 	return;
    526       break;
    527 
    528     case 1: /* pulse generator */
    529       /* do not advance counter if TCE = 0 */
    530       if(GET_TCR_TCE(controller) == 0)
    531 	return;
    532       break;
    533 
    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)
    538 	return;
    539       break;
    540 
    541     case 3: /* disabled */
    542       /* regardless of TCE, do not advance counter */
    543       return;
    544     }
    545 
    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. */
    550 
    551 
    552   /* find appropriate divisor etc. */
    553   if(GET_TCR_CCS(controller) == 0) /* internal system clock */
    554     {
    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)));
    558       else
    559 	divisor = controller->clock_ticks;
    560     }
    561   else
    562     {
    563       divisor = controller->ext_ticks;
    564     }
    565 
    566   /* how many times to increase counter? */
    567   quotient = warp / divisor;
    568   remainder = warp % divisor;
    569 
    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
    575      will equal 1. */
    576 
    577   controller->roundoff_ticks = remainder;
    578   controller->last_ticks = this_ticks;
    579   while(quotient > 0) /* Is it time to increment counter? */
    580     {
    581       /* next 24-bit counter value */
    582       unsigned_4 next_trr = (controller->trr + 1) % (1 << 24);
    583       quotient --;
    584 
    585       switch((int) GET_TCR_TMODE(controller))
    586 	{
    587 	case 0: /* interval timer mode */
    588 	  {
    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
    592 	       behavior. */
    593 	    if(controller->trr == controller->cpra ||
    594 	       next_trr == controller->cpra)
    595 	      {
    596 		/* likely hold CPRA value */
    597 		if(controller->trr == controller->cpra)
    598 		  next_trr = controller->cpra;
    599 
    600 		SET_TISR_TIIS(controller);
    601 
    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)
    607 		  {
    608 		    hw_port_event(me, INT_PORT, 1);
    609 		  }
    610 
    611 		/* Reset counter? */
    612 		if(GET_ITMR_TZCE(controller))
    613 		  {
    614 		    next_trr = 0;
    615 		  }
    616 	      }
    617 	  }
    618 	break;
    619 
    620 	case 1: /* pulse generator mode */
    621 	  {
    622 	    /* first trip point */
    623 	    if(next_trr == controller->cpra)
    624 	      {
    625 		/* flip flip-flop & report */
    626 		controller->ff ^= 1;
    627 		hw_port_event(me, FF_PORT, controller->ff);
    628 		SET_TISR_TPIAS(controller);
    629 
    630 		/* signal interrupt */
    631 		if(GET_PMGR_TPIAE(controller))
    632 		  {
    633 		    hw_port_event(me, INT_PORT, 1);
    634 		  }
    635 
    636 	      }
    637 	    /* second trip point */
    638 	    else if(next_trr == controller->cprb)
    639 	      {
    640 		/* flip flip-flop & report */
    641 		controller->ff ^= 1;
    642 		hw_port_event(me, FF_PORT, controller->ff);
    643 		SET_TISR_TPIBS(controller);
    644 
    645 		/* signal interrupt */
    646 		if(GET_PMGR_TPIBE(controller))
    647 		  {
    648 		    hw_port_event(me, INT_PORT, 1);
    649 		  }
    650 
    651 		/* clear counter */
    652 		next_trr = 0;
    653 	      }
    654 	  }
    655 	break;
    656 
    657 	case 2: /* watchdog timer mode */
    658 	  {
    659 	    /* watchdog timer expiry */
    660 	    if(next_trr == controller->cpra)
    661 	      {
    662 		SET_TISR_TWIS(controller);
    663 
    664 		/* signal interrupt */
    665 		if(GET_WTMR_TWIE(controller))
    666 		  {
    667 		    hw_port_event(me, INT_PORT, 1);
    668 		  }
    669 
    670 		/* clear counter */
    671 		next_trr = 0;
    672 	      }
    673 	  }
    674 	break;
    675 
    676 	case 3: /* disabled */
    677 	default:
    678 	  break;
    679 	}
    680 
    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 */
    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 };
    700