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