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