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